(function () { // constants var monthsAbbr = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]; var monthsFull = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ]; var daysAbbr = [ 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' ]; var daysFull = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ]; var dayNames = { 'su': 0, 'sun': 0, 'sunday': 0, 'mo': 1, 'mon': 1, 'monday': 1, 'tu': 2, 'tue': 2, 'tuesday': 2, 'we': 3, 'wed': 3, 'wednesday': 3, 'th': 4, 'thu': 4, 'thursday': 4, 'fr': 5, 'fri': 5, 'friday': 5, 'sa': 6, 'sat': 6, 'saturday': 6 }; var monthsAll = monthsFull.concat(monthsAbbr); var daysAll = [ 'su', 'sun', 'sunday', 'mo', 'mon', 'monday', 'tu', 'tue', 'tuesday', 'we', 'wed', 'wednesday', 'th', 'thu', 'thursday', 'fr', 'fri', 'friday', 'sa', 'sat', 'saturday' ]; var monthNames = { 'jan': 0, 'january': 0, 'feb': 1, 'february': 1, 'mar': 2, 'march': 2, 'apr': 3, 'april': 3, 'may': 4, 'jun': 5, 'june': 5, 'jul': 6, 'july': 6, 'aug': 7, 'august': 7, 'sep': 8, 'september': 8, 'oct': 9, 'october': 9, 'nov': 10, 'november': 10, 'dec': 11, 'december': 11 }; var daysInMonth = [ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]; // private helper functions /** @ignore */ function pad(str, length) { str = String(str); while (str.length < length) { str = '0' + str; } return str; } var isInteger = function (str) { if (str.match(/^(\d+)$/)) { return true; } return false; }; var getInt = function (str, i, minlength, maxlength) { for (var x = maxlength; x >= minlength; x--) { var token = str.substring(i, i + x); if (token.length < minlength) { return null; } if (isInteger(token)) { return token; } } return null; }; // static class methods var origParse = Date.parse; // ------------------------------------------------------------------ // getDateFromFormat( date_string , format_string ) // // This function takes a date string and a format string. It matches // If the date string matches the format string, it returns the // getTime() of the date. If it does not match, it returns NaN. // Original Author: Matt Kruse <matt@mattkruse.com> // WWW: http://www.mattkruse.com/ // Adapted from: http://www.mattkruse.com/javascript/date/source.html // ------------------------------------------------------------------ var getDateFromFormat = function (val, format) { val = val + ""; format = format + ""; var iVal = 0; var iFormat = 0; var c = ""; var token = ""; var token2 = ""; var x, y; var now = new Date(); var year = now.getYear(); var month = now.getMonth() + 1; var date = 1; var hh = 0; var mm = 0; var ss = 0; var ampm = ""; while (iFormat < format.length) { // Get next token from format string c = format.charAt(iFormat); token = ""; while ((format.charAt(iFormat) === c) && (iFormat < format.length)) { token += format.charAt(iFormat++); } // Extract contents of value based on format token if (token === "yyyy" || token === "yy" || token === "y") { if (token === "yyyy") { x = 4; y = 4; } if (token === "yy") { x = 2; y = 2; } if (token === "y") { x = 2; y = 4; } year = getInt(val, iVal, x, y); if (year === null) { return NaN; } iVal += year.length; if (year.length === 2) { if (year > 70) { year = 1900 + (year - 0); } else { year = 2000 + (year - 0); } } } else if (token === "MMM" || token === "NNN") { month = 0; for (var i = 0; i < monthsAll.length; i++) { var monthName = monthsAll[i]; if (val.substring(iVal, iVal + monthName.length).toLowerCase() === monthName.toLowerCase()) { if (token === "MMM" || (token === "NNN" && i > 11)) { month = i + 1; if (month > 12) { month -= 12; } iVal += monthName.length; break; } } } if ((month < 1) || (month > 12)) { return NaN; } } else if (token === "EE" || token === "E") { for (var n = 0; n < daysAll.length; n++) { var dayName = daysAll[n]; if (val.substring(iVal, iVal + dayName.length).toLowerCase() === dayName.toLowerCase()) { iVal += dayName.length; break; } } } else if (token === "MM" || token === "M") { month = getInt(val, iVal, token.length, 2); if (month === null || (month < 1) || (month > 12)) { return NaN; } iVal += month.length; } else if (token === "dd" || token === "d") { date = getInt(val, iVal, token.length, 2); if (date === null || (date < 1) || (date > 31)) { return NaN; } iVal += date.length; } else if (token === "hh" || token === "h") { hh = getInt(val, iVal, token.length, 2); if (hh === null || (hh < 1) || (hh > 12)) { return NaN; } iVal += hh.length; } else if (token === "HH" || token === "H") { hh = getInt(val, iVal, token.length, 2); if (hh === null || (hh < 0) || (hh > 23)) { return NaN; } iVal += hh.length; } else if (token === "KK" || token === "K") { hh = getInt(val, iVal, token.length, 2); if (hh === null || (hh < 0) || (hh > 11)) { return NaN; } iVal += hh.length; } else if (token === "kk" || token === "k") { hh = getInt(val, iVal, token.length, 2); if (hh === null || (hh < 1) || (hh > 24)) { return NaN; } iVal += hh.length; hh--; } else if (token === "mm" || token === "m") { mm = getInt(val, iVal, token.length, 2); if (mm === null || (mm < 0) || (mm > 59)) { return NaN; } iVal += mm.length; } else if (token === "ss" || token === "s") { ss = getInt(val, iVal, token.length, 2); if (ss === null || (ss < 0) || (ss > 59)) { return NaN; } iVal += ss.length; } else if (token === "a") { if (val.substring(iVal, iVal + 2).toLowerCase() === "am") { ampm = "AM"; } else if (val.substring(iVal, iVal + 2).toLowerCase() === "pm") { ampm = "PM"; } else { return NaN; } iVal += 2; } else { if (val.substring(iVal, iVal + token.length) !== token) { return NaN; } else { iVal += token.length; } } } // If there are any trailing characters left in the value, it doesn't match if (iVal !== val.length) { return NaN; } // Is date valid for month? if (month === 2) { // Check for leap year if (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)) { // leap year if (date > 29) { return NaN; } } else { if (date > 28) { return NaN; } } } if ((month === 4) || (month === 6) || (month === 9) || (month === 11)) { if (date > 30) { return NaN; } } // Correct hours value if (hh < 12 && ampm === "PM") { hh = hh - 0 + 12; } else if (hh > 11 && ampm === "AM") { hh -= 12; } var newdate = new Date(year, month - 1, date, hh, mm, ss); return newdate.getTime(); }; /** @ignore */ Date.parse = function (date, format) { if (format) { return getDateFromFormat(date, format); } var timestamp = origParse(date), minutesOffset = 0, match; if (isNaN(timestamp) && (match = /^(\d{4}|[+\-]\d{6})-(\d{2})-(\d{2})(?:[T ](\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3,}))?)?(?:(Z)|([+\-])(\d{2})(?::?(\d{2}))?))?/.exec(date))) { if (match[8] !== 'Z') { minutesOffset = +match[10] * 60 + (+match[11]); if (match[9] === '+') { minutesOffset = 0 - minutesOffset; } } match[7] = match[7] || '000'; timestamp = Date.UTC(+match[1], +match[2] - 1, +match[3], +match[4], +match[5] + minutesOffset, +match[6], +match[7].substr(0, 3)); } return timestamp; }; function polyfill(name, func) { if (Date.prototype[name] === undefined) { Date.prototype[name] = func; } } /** Returns new instance of Date object with the date set to today and the time set to midnight @returns {Date} Today's Date @function */ Date.today = function () { return new Date().clearTime(); }; /** Returns new instance of Date object with the date set to today and the time set to midnight in UTC @returns {Date} Today's Date in UTC @function */ Date.UTCtoday = function () { return new Date().clearUTCTime(); }; /** Returns new instance of Date object with the date set to tomorrow and the time set to midnight @returns {Date} Tomorrow's Date @function */ Date.tomorrow = function () { return Date.today().add({days: 1}); }; /** Returns new instance of Date object with the date set to tomorrow and the time set to midnight in UTC @returns {Date} Tomorrow's Date in UTC @function */ Date.UTCtomorrow = function () { return Date.UTCtoday().add({days: 1}); }; /** Returns new instance of Date object with the date set to yesterday and the time set to midnight @returns {Date} Yesterday's Date @function */ Date.yesterday = function () { return Date.today().add({days: -1}); }; /** Returns new instance of Date object with the date set to yesterday and the time set to midnight in UTC @returns {Date} Yesterday's Date in UTC @function */ Date.UTCyesterday = function () { return Date.UTCtoday().add({days: -1}); }; Date.validateDay = function (day, year, month) { var date = new Date(year, month, day); return (date.getFullYear() === year && date.getMonth() === month && date.getDate() === day); }; Date.validateYear = function (year) { return (year >= 0 && year <= 9999); }; Date.validateSecond = function (second) { return (second >= 0 && second < 60); }; Date.validateMonth = function (month) { return (month >= 0 && month < 12); }; Date.validateMinute = function (minute) { return (minute >= 0 && minute < 60); }; Date.validateMillisecond = function (milli) { return (milli >= 0 && milli < 1000); }; Date.validateHour = function (hour) { return (hour >= 0 && hour < 24); }; Date.compare = function (date1, date2) { if (date1.valueOf() < date2.valueOf()) { return -1; } else if (date1.valueOf() > date2.valueOf()) { return 1; } return 0; }; Date.equals = function (date1, date2) { return date1.valueOf() === date2.valueOf(); }; Date.getDayNumberFromName = function (name) { return dayNames[name.toLowerCase()]; }; Date.getMonthNumberFromName = function (name) { return monthNames[name.toLowerCase()]; }; Date.isLeapYear = function (year) { return (new Date(year, 1, 29).getDate() === 29); }; Date.getDaysInMonth = function (year, month) { if (month === 1) { return Date.isLeapYear(year) ? 29 : 28; } return daysInMonth[month]; }; polyfill('getMonthAbbr', function () { return monthsAbbr[this.getMonth()]; }); polyfill('getMonthName', function () { return monthsFull[this.getMonth()]; }); polyfill('getUTCOffset', function () { var tz = pad(Math.abs(this.getTimezoneOffset() / 0.6), 4); if (this.getTimezoneOffset() > 0) { tz = '-' + tz; } return tz; }); polyfill('toCLFString', function () { return pad(this.getDate(), 2) + '/' + this.getMonthAbbr() + '/' + this.getFullYear() + ':' + pad(this.getHours(), 2) + ':' + pad(this.getMinutes(), 2) + ':' + pad(this.getSeconds(), 2) + ' ' + this.getUTCOffset(); }); polyfill('toYMD', function (separator) { separator = typeof separator === 'undefined' ? '-' : separator; return this.getFullYear() + separator + pad(this.getMonth() + 1, 2) + separator + pad(this.getDate(), 2); }); polyfill('toDBString', function () { return this.getUTCFullYear() + '-' + pad(this.getUTCMonth() + 1, 2) + '-' + pad(this.getUTCDate(), 2) + ' ' + pad(this.getUTCHours(), 2) + ':' + pad(this.getUTCMinutes(), 2) + ':' + pad(this.getUTCSeconds(), 2); }); polyfill('clearTime', function () { this.setHours(0); this.setMinutes(0); this.setSeconds(0); this.setMilliseconds(0); return this; }); polyfill('clearUTCTime', function () { this.setUTCHours(0); this.setUTCMinutes(0); this.setUTCSeconds(0); this.setUTCMilliseconds(0); return this; }); polyfill('add', function (obj) { if (obj.milliseconds !== undefined) { this.setMilliseconds(this.getMilliseconds() + obj.milliseconds); } if (obj.seconds !== undefined) { this.setSeconds(this.getSeconds() + obj.seconds); } if (obj.minutes !== undefined) { this.setMinutes(this.getMinutes() + obj.minutes); } if (obj.hours !== undefined) { this.setHours(this.getHours() + obj.hours); } if (obj.days !== undefined) { this.setDate(this.getDate() + obj.days); } if (obj.weeks !== undefined) { this.setDate(this.getDate() + (obj.weeks * 7)); } if (obj.months !== undefined) { this.setMonth(this.getMonth() + obj.months); } if (obj.years !== undefined) { this.setFullYear(this.getFullYear() + obj.years); } return this; }); polyfill('addMilliseconds', function (milliseconds) { return this.add({ milliseconds: milliseconds }); }); polyfill('addSeconds', function (seconds) { return this.add({ seconds: seconds }); }); polyfill('addMinutes', function (minutes) { return this.add({ minutes: minutes }); }); polyfill('addHours', function (hours) { return this.add({ hours: hours }); }); polyfill('addDays', function (days) { return this.add({ days: days }); }); polyfill('addWeeks', function (weeks) { return this.add({ days: (weeks * 7) }); }); polyfill('addMonths', function (months) { return this.add({ months: months }); }); polyfill('addYears', function (years) { return this.add({ years: years }); }); polyfill('setTimeToNow', function () { var n = new Date(); this.setMilliseconds(n.getMilliseconds()); this.setSeconds(n.getSeconds()); this.setMinutes(n.getMinutes()); this.setHours(n.getHours()); }); polyfill('clone', function () { return new Date(this.valueOf()); }); polyfill('between', function (start, end) { return (this.valueOf() >= start.valueOf() && this.valueOf() <= end.valueOf()); }); polyfill('compareTo', function (date) { return Date.compare(this, date); }); polyfill('equals', function (date) { return Date.equals(this, date); }); polyfill('isAfter', function (date) { date = date ? date : new Date(); return (this.compareTo(date) > 0); }); polyfill('isBefore', function (date) { date = date ? date : new Date(); return (this.compareTo(date) < 0); }); polyfill('getDaysBetween', function (date) { return ((date.clone().valueOf() - this.valueOf()) / 86400000) | 0; }); polyfill('getHoursBetween', function (date) { return ((date.clone().valueOf() - this.valueOf()) / 3600000) | 0; }); polyfill('getMinutesBetween', function (date) { return ((date.clone().valueOf() - this.valueOf()) / 60000) | 0; }); polyfill('getSecondsBetween', function (date) { return ((date.clone().valueOf() - this.valueOf()) / 1000) | 0; }); polyfill('getMillisecondsBetween', function (date) { return ((date.clone().valueOf() - this.valueOf())) | 0; }); polyfill('getOrdinalNumber', function () { return Math.ceil((this.clone().clearTime() - new Date(this.getFullYear(), 0, 1)) / 86400000) + 1; }); polyfill('toFormat', function (format) { return toFormat(format, getReplaceMap(this)); }); polyfill('toUTCFormat', function (format) { return toFormat(format, getUTCReplaceMap(this)); }); var toFormat = function(format, replaceMap) { var f = [ format ], i, l, s; var replace = function (str, rep) { var i = 0, l = f.length, j, ll, t, n = []; for (; i < l; i++) { if (typeof f[i] == 'string') { t = f[i].split(str); for (j = 0, ll = t.length - 1; j < ll; j++) { n.push(t[j]); n.push([rep]); // replacement pushed as non-string } n.push(t[ll]); } else { // must be a replacement, don't process, just push n.push(f[i]); } } f = n; }; for (i in replaceMap) { replace(i, replaceMap[i]); } s = ''; for (i = 0, l = f.length; i < l; i++) s += typeof f[i] == 'string' ? f[i] : f[i][0]; return f.join(''); }; var getReplaceMap = function(date) { var hours = (date.getHours() % 12) ? date.getHours() % 12 : 12; return { 'YYYY': date.getFullYear(), 'YY': String(date.getFullYear()).slice(-2), 'MMMM': monthsFull[date.getMonth()], 'MMM': monthsAbbr[date.getMonth()], 'MM': pad(date.getMonth() + 1, 2), 'MI': pad(date.getMinutes(), 2), 'M': date.getMonth() + 1, 'DDDD': daysFull[date.getDay()], 'DDD': daysAbbr[date.getDay()], 'DD': pad(date.getDate(), 2), 'D': date.getDate(), 'HH24': pad(date.getHours(), 2), 'HH': pad(hours, 2), 'H': hours, 'SS': pad(date.getSeconds(), 2), 'PP': (date.getHours() >= 12) ? 'PM' : 'AM', 'P': (date.getHours() >= 12) ? 'pm' : 'am', 'LL': pad(date.getMilliseconds(), 3) }; }; var getUTCReplaceMap = function(date) { var hours = (date.getUTCHours() % 12) ? date.getUTCHours() % 12 : 12; return { 'YYYY': date.getUTCFullYear(), 'YY': String(date.getUTCFullYear()).slice(-2), 'MMMM': monthsFull[date.getUTCMonth()], 'MMM': monthsAbbr[date.getUTCMonth()], 'MM': pad(date.getUTCMonth() + 1, 2), 'MI': pad(date.getUTCMinutes(), 2), 'M': date.getUTCMonth() + 1, 'DDDD': daysFull[date.getUTCDay()], 'DDD': daysAbbr[date.getUTCDay()], 'DD': pad(date.getUTCDate(), 2), 'D': date.getUTCDate(), 'HH24': pad(date.getUTCHours(), 2), 'HH': pad(hours, 2), 'H': hours, 'SS': pad(date.getUTCSeconds(), 2), 'PP': (date.getUTCHours() >= 12) ? 'PM' : 'AM', 'P': (date.getUTCHours() >= 12) ? 'pm' : 'am', 'LL': pad(date.getUTCMilliseconds(), 3) }; }; }());