diff --git a/build/ical.js b/build/ical.js index c4977593..3113c7da 100644 --- a/build/ical.js +++ b/build/ical.js @@ -4944,10 +4944,13 @@ ICAL.TimezoneService = (function() { /** * Calculate the day of week. + * @param {ICAL.Time.weekDay=} aWeekStart + * The week start weekday, defaults to SUNDAY * @return {ICAL.Time.weekDay} */ - dayOfWeek: function icaltime_dayOfWeek() { - var dowCacheKey = (this.year << 9) + (this.month << 5) + this.day; + dayOfWeek: function icaltime_dayOfWeek(aWeekStart) { + var firstDow = aWeekStart || ICAL.Time.SUNDAY; + var dowCacheKey = (this.year << 12) + (this.month << 8) + (this.day << 3) + firstDow; if (dowCacheKey in ICAL.Time._dowCache) { return ICAL.Time._dowCache[dowCacheKey]; } @@ -4965,8 +4968,8 @@ ICAL.TimezoneService = (function() { h += 5; } - // Normalize to 1 = sunday - h = ((h + 6) % 7) + 1; + // Normalize to 1 = wkst + h = ((h + 7 - firstDow) % 7) + 1; ICAL.Time._dowCache[dowCacheKey] = h; return h; }, @@ -6596,26 +6599,35 @@ ICAL.TimezoneService = (function() { * into a numeric value of that day. * * @param {String} string The iCalendar day name + * @param {ICAL.Time.weekDay=} aWeekStart + * The week start weekday, defaults to SUNDAY * @return {Number} Numeric value of given day */ - ICAL.Recur.icalDayToNumericDay = function toNumericDay(string) { + ICAL.Recur.icalDayToNumericDay = function toNumericDay(string, aWeekStart) { //XXX: this is here so we can deal // with possibly invalid string values. - - return DOW_MAP[string]; + var firstDow = aWeekStart || ICAL.Time.SUNDAY; + return ((DOW_MAP[string] - firstDow + 7) % 7) + 1; }; /** * Convert a numeric day value into its ical representation (SU, MO, etc..) * * @param {Number} num Numeric value of given day + * @param {ICAL.Time.weekDay=} aWeekStart + * The week start weekday, defaults to SUNDAY * @return {String} The ICAL day value, e.g SU,MO,... */ - ICAL.Recur.numericDayToIcalDay = function toIcalDay(num) { + ICAL.Recur.numericDayToIcalDay = function toIcalDay(num, aWeekStart) { //XXX: this is here so we can deal with possibly invalid number values. // Also, this allows consistent mapping between day numbers and day // names for external users. - return REVERSE_DOW_MAP[num]; + var firstDow = aWeekStart || ICAL.Time.SUNDAY; + var dow = (num + firstDow - ICAL.Time.SUNDAY); + if (dow > 7) { + dow -= 7; + } + return REVERSE_DOW_MAP[dow]; }; var VALID_DAY_NAMES = /^(SU|MO|TU|WE|TH|FR|SA)$/; @@ -6955,7 +6967,7 @@ ICAL.RecurIterator = (function() { if ("BYDAY" in parts) { // libical does this earlier when the rule is loaded, but we postpone to // now so we can preserve the original order. - this.sort_byday_rules(parts.BYDAY, this.rule.wkst); + this.sort_byday_rules(parts.BYDAY); } // If the BYYEARDAY appares, no other date rule part may appear @@ -6998,11 +7010,11 @@ ICAL.RecurIterator = (function() { if (this.rule.freq == "WEEKLY") { if ("BYDAY" in parts) { - var bydayParts = this.ruleDayOfWeek(parts.BYDAY[0]); + var bydayParts = this.ruleDayOfWeek(parts.BYDAY[0], this.rule.wkst); var pos = bydayParts[0]; var dow = bydayParts[1]; - var wkdy = dow - this.last.dayOfWeek(); - if ((this.last.dayOfWeek() < dow && wkdy >= 0) || wkdy < 0) { + var wkdy = dow - this.last.dayOfWeek(this.rule.wkst); + if ((this.last.dayOfWeek(this.rule.wkst) < dow && wkdy >= 0) || wkdy < 0) { // Initial time is after first day of BYDAY data this.last.day += wkdy; } @@ -7622,11 +7634,16 @@ ICAL.RecurIterator = (function() { this.last.month = next.month; }, - ruleDayOfWeek: function ruleDayOfWeek(dow) { + /** + * @param dow (eg: '1TU', '-1MO') + * @param {ICAL.Time.weekDay=} aWeekStart The week start weekday + * @return [pos, numericDow] (eg: [1, 3]) numericDow is relative to aWeekStart + */ + ruleDayOfWeek: function ruleDayOfWeek(dow, aWeekStart) { var matches = dow.match(/([+-]?[0-9])?(MO|TU|WE|TH|FR|SA|SU)/); if (matches) { var pos = parseInt(matches[1] || 0, 10); - dow = ICAL.Recur.icalDayToNumericDay(matches[2]); + dow = ICAL.Recur.icalDayToNumericDay(matches[2], aWeekStart); return [pos, dow]; } else { return [0, 0]; @@ -8079,15 +8096,11 @@ ICAL.RecurIterator = (function() { return false; }, - sort_byday_rules: function icalrecur_sort_byday_rules(aRules, aWeekStart) { + sort_byday_rules: function icalrecur_sort_byday_rules(aRules) { for (var i = 0; i < aRules.length; i++) { for (var j = 0; j < i; j++) { - var one = this.ruleDayOfWeek(aRules[j])[1]; - var two = this.ruleDayOfWeek(aRules[i])[1]; - one -= aWeekStart; - two -= aWeekStart; - if (one < 0) one += 7; - if (two < 0) two += 7; + var one = this.ruleDayOfWeek(aRules[j], this.rule.wkst)[1]; + var two = this.ruleDayOfWeek(aRules[i], this.rule.wkst)[1]; if (one > two) { var tmp = aRules[i]; diff --git a/build/ical.min.js b/build/ical.min.js index 36c1a2f6..14d3144a 100644 --- a/build/ical.min.js +++ b/build/ical.min.js @@ -1,2 +1,2 @@ -"object"==typeof module?ICAL=module.exports:"object"!=typeof ICAL&&(this.ICAL={}),ICAL.foldLength=75,ICAL.newLineChar="\r\n",ICAL.helpers={updateTimezones:function(t){var e,r,n,i,a,s;if(!t||"vcalendar"!==t.name)return t;for(e=t.getAllSubcomponents(),r=[],n={},a=0;a>18&63,r=a>>12&63,n=a>>6&63,i=63&a,c[u++]=s.charAt(e)+s.charAt(r)+s.charAt(n)+s.charAt(i),o>16&255,r=s>>8&255,n=255&s,c[h++]=64==i?String.fromCharCode(e):64==a?String.fromCharCode(e,r):String.fromCharCode(e,r,n),u=this.changes.length)break}var s=this.changes[n];if(s.utcOffset-s.prevUtcOffset<0&&0=this.changes.length?this.changes.length-1:e},_ensureCoverage:function(t){if(-1==ICAL.Timezone._minimumExpansionYear){var e=ICAL.Time.now();ICAL.Timezone._minimumExpansionYear=e.year}var r=t;if(rICAL.Timezone.MAX_YEAR&&(r=ICAL.Timezone.MAX_YEAR),!this.changes.length||this.expandedUntilYeart)&&l);)n.year=l.year,n.month=l.month,n.day=l.day,n.hour=l.hour,n.minute=l.minute,n.second=l.second,n.isDate=l.isDate,ICAL.Timezone.adjust_change(n,0,0,0,-n.prevUtcOffset),r.push(n)}}else(n=s()).year=i.year,n.month=i.month,n.day=i.day,n.hour=i.hour,n.minute=i.minute,n.second=i.second,ICAL.Timezone.adjust_change(n,0,0,0,-n.prevUtcOffset),r.push(n);return r},toString:function(){return this.tznames?this.tznames:this.tzid}},ICAL.Timezone._compare_change_fn=function(t,e){return t.yeare.year?1:t.monthe.month?1:t.daye.day?1:t.houre.hour?1:t.minutee.minute?1:t.seconde.second?1:0},ICAL.Timezone.convert_time=function(t,e,r){if(t.isDate||e.tzid==r.tzid||e==ICAL.Timezone.localTimezone||r==ICAL.Timezone.localTimezone)return t.zone=r,t;var n=e.utcOffset(t);return t.adjust(0,0,0,-n),n=r.utcOffset(t),t.adjust(0,0,0,n),null},ICAL.Timezone.fromData=function(t){return(new ICAL.Timezone).fromData(t)},ICAL.Timezone.utcTimezone=ICAL.Timezone.fromData({tzid:"UTC"}),ICAL.Timezone.localTimezone=ICAL.Timezone.fromData({tzid:"floating"}),ICAL.Timezone.adjust_change=function(t,e,r,n,i){return ICAL.Time.prototype.adjust.call(t,e,r,n,i,t)},ICAL.Timezone._minimumExpansionYear=-1,ICAL.Timezone.MAX_YEAR=2035,ICAL.Timezone.EXTRA_COVERAGE=5}(),ICAL.TimezoneService=function(){var r,t={reset:function(){r=Object.create(null);var t=ICAL.Timezone.utcTimezone;r.Z=t,r.UTC=t,r.GMT=t},has:function(t){return!!r[t]},get:function(t){return r[t]},register:function(t,e){if(t instanceof ICAL.Component&&"vtimezone"===t.name&&(t=(e=new ICAL.Timezone(t)).tzid),!(e instanceof ICAL.Timezone))throw new TypeError("timezone must be ICAL.Timezone or ICAL.Component");r[t]=e},remove:function(t){return delete r[t]}};return t.reset(),t}(),function(){function t(e){Object.defineProperty(ICAL.Time.prototype,e,{get:function(){return this._pendingNormalization&&(this._normalize(),this._pendingNormalization=!1),this._time[e]},set:function(t){return"isDate"===e&&t&&!this._time.isDate&&this.adjust(0,0,0,0),this._cachedUnixTime=null,this._pendingNormalization=!0,this._time[e]=t}})}ICAL.Time=function(t,e){var r=(this.wrappedJSObject=this)._time=Object.create(null);r.year=0,r.month=1,r.day=1,r.hour=0,r.minute=0,r.second=0,r.isDate=!1,this.fromData(t,e)},ICAL.Time._dowCache={},ICAL.Time._wnCache={},ICAL.Time.prototype={icalclass:"icaltime",_cachedUnixTime:null,get icaltype(){return this.isDate?"date":"date-time"},zone:null,_pendingNormalization:!1,clone:function(){return new ICAL.Time(this._time,this.zone)},reset:function(){this.fromData(ICAL.Time.epochTime),this.zone=ICAL.Timezone.utcTimezone},resetTo:function(t,e,r,n,i,a,s){this.fromData({year:t,month:e,day:r,hour:n,minute:i,second:a,zone:s})},fromJSDate:function(t,e){return t?e?(this.zone=ICAL.Timezone.utcTimezone,this.year=t.getUTCFullYear(),this.month=t.getUTCMonth()+1,this.day=t.getUTCDate(),this.hour=t.getUTCHours(),this.minute=t.getUTCMinutes(),this.second=t.getUTCSeconds()):(this.zone=ICAL.Timezone.localTimezone,this.year=t.getFullYear(),this.month=t.getMonth()+1,this.day=t.getDate(),this.hour=t.getHours(),this.minute=t.getMinutes(),this.second=t.getSeconds()):this.reset(),this._cachedUnixTime=null,this},fromData:function(t,e){if(t)for(var r in t)if(Object.prototype.hasOwnProperty.call(t,r)){if("icaltype"===r)continue;this[r]=t[r]}if(e&&(this.zone=e),!t||"isDate"in t?t&&"isDate"in t&&(this.isDate=t.isDate):this.isDate=!("hour"in t),t&&"timezone"in t){var n=ICAL.TimezoneService.get(t.timezone);this.zone=n||ICAL.Timezone.localTimezone}return t&&"zone"in t&&(this.zone=t.zone),this.zone||(this.zone=ICAL.Timezone.localTimezone),this._cachedUnixTime=null,this},dayOfWeek:function(){var t=(this.year<<9)+(this.month<<5)+this.day;if(t in ICAL.Time._dowCache)return ICAL.Time._dowCache[t];var e=this.day,r=this.month+(this.month<3?12:0),n=this.year-(this.month<3?1:0),i=e+n+ICAL.helpers.trunc(26*(r+1)/10)+ICAL.helpers.trunc(n/4);return i=((i+=6*ICAL.helpers.trunc(n/100)+ICAL.helpers.trunc(n/400))+6)%7+1,ICAL.Time._dowCache[t]=i},dayOfYear:function(){var t=ICAL.Time.isLeapYear(this.year)?1:0;return ICAL.Time.daysInYearPassedMonth[t][this.month-1]+this.day},startOfWeek:function(t){var e=t||ICAL.Time.SUNDAY,r=this.clone();return r.day-=(this.dayOfWeek()+7-e)%7,r.isDate=!0,r.hour=0,r.minute=0,r.second=0,r},endOfWeek:function(t){var e=t||ICAL.Time.SUNDAY,r=this.clone();return r.day+=(7-this.dayOfWeek()+e-ICAL.Time.SUNDAY)%7,r.isDate=!0,r.hour=0,r.minute=0,r.second=0,r},startOfMonth:function(){var t=this.clone();return t.day=1,t.isDate=!0,t.hour=0,t.minute=0,t.second=0,t},endOfMonth:function(){var t=this.clone();return t.day=ICAL.Time.daysInMonth(t.month,t.year),t.isDate=!0,t.hour=0,t.minute=0,t.second=0,t},startOfYear:function(){var t=this.clone();return t.day=1,t.month=1,t.isDate=!0,t.hour=0,t.minute=0,t.second=0,t},endOfYear:function(){var t=this.clone();return t.day=31,t.month=12,t.isDate=!0,t.hour=0,t.minute=0,t.second=0,t},startDoyWeek:function(t){var e=t||ICAL.Time.SUNDAY,r=this.dayOfWeek()-e;return r<0&&(r+=7),this.dayOfYear()-r},getDominicalLetter:function(){return ICAL.Time.getDominicalLetter(this.year)},nthWeekDay:function(t,e){var r,n=ICAL.Time.daysInMonth(this.month,this.year),i=e,a=0,s=this.clone();if(0<=i){s.day=1,0!=i&&i--,a=s.day;var o=t-s.dayOfWeek();o<0&&(o+=7),a+=o,a-=t,r=t}else{s.day=n,i++,(r=s.dayOfWeek()-t)<0&&(r+=7),r=n-r}return a+(r+=7*i)},isNthWeekDay:function(t,e){var r=this.dayOfWeek();return 0===e&&r===t||this.nthWeekDay(t,e)===this.day},weekNumber:function(t){var e,r=(this.year<<12)+(this.month<<8)+(this.day<<3)+t;if(r in ICAL.Time._wnCache)return ICAL.Time._wnCache[r];var n=this.clone();n.isDate=!0;var i=this.year;12==n.month&&25ICAL.Time.daysInYearPassedMonth[a][12])return a=ICAL.Time.isLeapYear(r)?1:0,n-=ICAL.Time.daysInYearPassedMonth[a][12],r++,ICAL.Time.fromDayOfYear(n,r);i.year=r,i.isDate=!0;for(var s=11;0<=s;s--)if(n>ICAL.Time.daysInYearPassedMonth[a][s]){i.month=s+1,i.day=n-ICAL.Time.daysInYearPassedMonth[a][s];break}return i.auto_normalize=!0,i},ICAL.Time.fromStringv2=function(t){return new ICAL.Time({year:parseInt(t.substr(0,4),10),month:parseInt(t.substr(5,2),10),day:parseInt(t.substr(8,2),10),isDate:!0})},ICAL.Time.fromDateString=function(t){return new ICAL.Time({year:ICAL.helpers.strictParseInt(t.substr(0,4)),month:ICAL.helpers.strictParseInt(t.substr(5,2)),day:ICAL.helpers.strictParseInt(t.substr(8,2)),isDate:!0})},ICAL.Time.fromDateTimeString=function(t,e){if(t.length<19)throw new Error('invalid date-time value: "'+t+'"');var r;return t[19]&&"Z"===t[19]?r="Z":e&&(r=e.getParameter("tzid")),new ICAL.Time({year:ICAL.helpers.strictParseInt(t.substr(0,4)),month:ICAL.helpers.strictParseInt(t.substr(5,2)),day:ICAL.helpers.strictParseInt(t.substr(8,2)),hour:ICAL.helpers.strictParseInt(t.substr(11,2)),minute:ICAL.helpers.strictParseInt(t.substr(14,2)),second:ICAL.helpers.strictParseInt(t.substr(17,2)),timezone:r})},ICAL.Time.fromString=function(t){return 10ICAL.Time.THURSDAY&&(r.day+=7),i>ICAL.Time.THURSDAY&&(r.day-=7),r.day-=n-i,r},ICAL.Time.getDominicalLetter=function(t){var e="GFEDCBA",r=(t+(t/4|0)+(t/400|0)-(t/100|0)-1)%7;return ICAL.Time.isLeapYear(t)?e[(6+r)%7]+e[r]:e[r]},ICAL.Time.epochTime=ICAL.Time.fromData({year:1970,month:1,day:1,hour:0,minute:0,second:0,isDate:!1,timezone:"Z"}),ICAL.Time._cmp_attr=function(t,e,r){return t[r]>e[r]?1:t[r] '+e);if(void 0!==r&&rs||0==this.last.day)throw new Error("Malformed values in BYDAY part")}else if(this.has_by_data("BYMONTHDAY")&&this.last.day<0){s=ICAL.Time.daysInMonth(this.last.month,this.last.year);this.last.day=s+this.last.day+1}},next:function(){var t,e=this.last?this.last.clone():null;if(this.rule.count&&this.occurrence_number>=this.rule.count||this.rule.until&&0i)){if(n<0)n=i+(n+1);else if(0===n)continue;-1===a.indexOf(n)&&a.push(n)}return a.sort(function(t,e){return t-e})},_byDayAndMonthDay:function(t){var e,r,n,i,a=this.by_data.BYDAY,s=0,o=a.length,u=0,h=this,c=this.last.day;function l(){for(i=ICAL.Time.daysInMonth(h.last.month,h.last.year),e=h.normalizeByMonthDayRules(h.last.year,h.last.month,h.by_data.BYMONTHDAY),n=e.length;e[s]<=c&&(!t||e[s]!=c)&&s=this.by_data.BYMONTHDAY.length&&(this.by_indices.BYMONTHDAY=0,this.increment_month());e=ICAL.Time.daysInMonth(this.last.month,this.last.year);(a=this.by_data.BYMONTHDAY[this.by_indices.BYMONTHDAY])<0&&(a=e+a+1),ee?t=0:this.last.day=this.by_data.BYMONTHDAY[0]}return t},next_weekday_by_week:function(){var t=0;if(0==this.next_hour())return t;if(!this.has_by_data("BYDAY"))return 1;for(;;){var e=new ICAL.Time;this.by_indices.BYDAY++,this.by_indices.BYDAY==Object.keys(this.by_data.BYDAY).length&&(this.by_indices.BYDAY=0,t=1);var r=this.by_data.BYDAY[this.by_indices.BYDAY],n=this.ruleDayOfWeek(r)[1];(n-=this.rule.wkst)<0&&(n+=7),e.year=this.last.year,e.month=this.last.month,e.day=this.last.day;var i=e.startDoyWeek(this.rule.wkst);if(!(n+i<1)||t){var a=ICAL.Time.fromDayOfYear(i+n,this.last.year);return this.last.year=a.year,this.last.month=a.month,this.last.day=a.day,t}}},next_year:function(){if(0==this.next_hour())return 0;if(++this.days_index==this.days.length)for(this.days_index=0;this.increment_year(this.rule.interval),this.expand_year_days(this.last.year),0==this.days.length;);return this._nextByYearDay(),1},_nextByYearDay:function(){var t=this.days[this.days_index],e=this.last.year;t<1&&(t+=1,e+=1);var r=ICAL.Time.fromDayOfYear(t,e);this.last.day=r.day,this.last.month=r.month},ruleDayOfWeek:function(t){var e=t.match(/([+-]?[0-9])?(MO|TU|WE|TH|FR|SA|SU)/);return e?[parseInt(e[1]||0,10),t=ICAL.Recur.icalDayToNumericDay(e[2])]:[0,0]},next_generic:function(t,e,r,n,i){var a=t in this.by_data,s=this.rule.freq==e,o=0;if(i&&0==this[i]())return o;if(a){this.by_indices[t]++;this.by_indices[t];var u=this.by_data[t];this.by_indices[t]==u.length&&(this.by_indices[t]=0,o=1),this.last[r]=u[this.by_indices[t]]}else s&&this["increment_"+r](this.rule.interval);return a&&o&&s&&this["increment_"+n](1),o},increment_monthday:function(t){for(var e=0;er&&(this.last.day-=r,this.increment_month())}},increment_month:function(){if(this.last.day=1,this.has_by_data("BYMONTH"))this.by_indices.BYMONTH++,this.by_indices.BYMONTH==this.by_data.BYMONTH.length&&(this.by_indices.BYMONTH=0,this.increment_year(1)),this.last.month=this.by_data.BYMONTH[this.by_indices.BYMONTH];else{"MONTHLY"==this.rule.freq?this.last.month+=this.rule.interval:this.last.month++,this.last.month--;var t=ICAL.helpers.trunc(this.last.month/12);this.last.month%=12,this.last.month++,0!=t&&this.increment_year(t)}},increment_year:function(t){this.last.year+=t},increment_generic:function(t,e,r,n){this.last[e]+=t;var i=ICAL.helpers.trunc(this.last[e]/r);this.last[e]%=r,0!=i&&this["increment_"+n](i)},has_by_data:function(t){return t in this.rule.parts},expand_year_days:function(t){var e=new ICAL.Time;this.days=[];var r={},n=["BYDAY","BYWEEKNO","BYMONTHDAY","BYMONTH","BYYEARDAY"];for(var i in n)if(n.hasOwnProperty(i)){var a=n[i];a in this.rule.parts&&(r[a]=this.rule.parts[a])}if("BYMONTH"in r&&"BYWEEKNO"in r){var s=1,o={};e.year=t,e.isDate=!0;for(var u=0;ue[0]?1:e[0]>t[0]?-1:0}return t.prototype={THISANDFUTURE:"THISANDFUTURE",exceptions:null,strictExceptions:!1,relateException:function(t){if(this.isRecurrenceException())throw new Error("cannot relate exception to exceptions");if(t instanceof ICAL.Component&&(t=new ICAL.Event(t)),this.strictExceptions&&t.uid!==this.uid)throw new Error("attempted to relate unrelated exception");var e=t.recurrenceId.toString();if((this.exceptions[e]=t).modifiesFuture()){var r=[t.recurrenceId.toUnixTime(),e],n=ICAL.helpers.binsearchInsert(this.rangeExceptions,r,i);this.rangeExceptions.splice(n,0,r)}},modifiesFuture:function(){return!!this.component.hasProperty("recurrence-id")&&this.component.getFirstProperty("recurrence-id").getParameter("range")===this.THISANDFUTURE},findRangeException:function(t){if(!this.rangeExceptions.length)return null;var e=t.toUnixTime(),r=ICAL.helpers.binsearchInsert(this.rangeExceptions,[e],i);if(--r<0)return null;var n=this.rangeExceptions[r];return e>18&63,r=a>>12&63,n=a>>6&63,i=63&a,c[u++]=s.charAt(e)+s.charAt(r)+s.charAt(n)+s.charAt(i),o>16&255,r=s>>8&255,n=255&s,c[h++]=64==i?String.fromCharCode(e):64==a?String.fromCharCode(e,r):String.fromCharCode(e,r,n),u=this.changes.length)break}var s=this.changes[n];if(s.utcOffset-s.prevUtcOffset<0&&0=this.changes.length?this.changes.length-1:e},_ensureCoverage:function(t){if(-1==ICAL.Timezone._minimumExpansionYear){var e=ICAL.Time.now();ICAL.Timezone._minimumExpansionYear=e.year}var r=t;if(rICAL.Timezone.MAX_YEAR&&(r=ICAL.Timezone.MAX_YEAR),!this.changes.length||this.expandedUntilYeart)&&l);)n.year=l.year,n.month=l.month,n.day=l.day,n.hour=l.hour,n.minute=l.minute,n.second=l.second,n.isDate=l.isDate,ICAL.Timezone.adjust_change(n,0,0,0,-n.prevUtcOffset),r.push(n)}}else(n=s()).year=i.year,n.month=i.month,n.day=i.day,n.hour=i.hour,n.minute=i.minute,n.second=i.second,ICAL.Timezone.adjust_change(n,0,0,0,-n.prevUtcOffset),r.push(n);return r},toString:function(){return this.tznames?this.tznames:this.tzid}},ICAL.Timezone._compare_change_fn=function(t,e){return t.yeare.year?1:t.monthe.month?1:t.daye.day?1:t.houre.hour?1:t.minutee.minute?1:t.seconde.second?1:0},ICAL.Timezone.convert_time=function(t,e,r){if(t.isDate||e.tzid==r.tzid||e==ICAL.Timezone.localTimezone||r==ICAL.Timezone.localTimezone)return t.zone=r,t;var n=e.utcOffset(t);return t.adjust(0,0,0,-n),n=r.utcOffset(t),t.adjust(0,0,0,n),null},ICAL.Timezone.fromData=function(t){return(new ICAL.Timezone).fromData(t)},ICAL.Timezone.utcTimezone=ICAL.Timezone.fromData({tzid:"UTC"}),ICAL.Timezone.localTimezone=ICAL.Timezone.fromData({tzid:"floating"}),ICAL.Timezone.adjust_change=function(t,e,r,n,i){return ICAL.Time.prototype.adjust.call(t,e,r,n,i,t)},ICAL.Timezone._minimumExpansionYear=-1,ICAL.Timezone.MAX_YEAR=2035,ICAL.Timezone.EXTRA_COVERAGE=5}(),ICAL.TimezoneService=function(){var r,t={reset:function(){r=Object.create(null);var t=ICAL.Timezone.utcTimezone;r.Z=t,r.UTC=t,r.GMT=t},has:function(t){return!!r[t]},get:function(t){return r[t]},register:function(t,e){if(t instanceof ICAL.Component&&"vtimezone"===t.name&&(t=(e=new ICAL.Timezone(t)).tzid),!(e instanceof ICAL.Timezone))throw new TypeError("timezone must be ICAL.Timezone or ICAL.Component");r[t]=e},remove:function(t){return delete r[t]}};return t.reset(),t}(),function(){function t(e){Object.defineProperty(ICAL.Time.prototype,e,{get:function(){return this._pendingNormalization&&(this._normalize(),this._pendingNormalization=!1),this._time[e]},set:function(t){return"isDate"===e&&t&&!this._time.isDate&&this.adjust(0,0,0,0),this._cachedUnixTime=null,this._pendingNormalization=!0,this._time[e]=t}})}ICAL.Time=function(t,e){var r=(this.wrappedJSObject=this)._time=Object.create(null);r.year=0,r.month=1,r.day=1,r.hour=0,r.minute=0,r.second=0,r.isDate=!1,this.fromData(t,e)},ICAL.Time._dowCache={},ICAL.Time._wnCache={},ICAL.Time.prototype={icalclass:"icaltime",_cachedUnixTime:null,get icaltype(){return this.isDate?"date":"date-time"},zone:null,_pendingNormalization:!1,clone:function(){return new ICAL.Time(this._time,this.zone)},reset:function(){this.fromData(ICAL.Time.epochTime),this.zone=ICAL.Timezone.utcTimezone},resetTo:function(t,e,r,n,i,a,s){this.fromData({year:t,month:e,day:r,hour:n,minute:i,second:a,zone:s})},fromJSDate:function(t,e){return t?e?(this.zone=ICAL.Timezone.utcTimezone,this.year=t.getUTCFullYear(),this.month=t.getUTCMonth()+1,this.day=t.getUTCDate(),this.hour=t.getUTCHours(),this.minute=t.getUTCMinutes(),this.second=t.getUTCSeconds()):(this.zone=ICAL.Timezone.localTimezone,this.year=t.getFullYear(),this.month=t.getMonth()+1,this.day=t.getDate(),this.hour=t.getHours(),this.minute=t.getMinutes(),this.second=t.getSeconds()):this.reset(),this._cachedUnixTime=null,this},fromData:function(t,e){if(t)for(var r in t)if(Object.prototype.hasOwnProperty.call(t,r)){if("icaltype"===r)continue;this[r]=t[r]}if(e&&(this.zone=e),!t||"isDate"in t?t&&"isDate"in t&&(this.isDate=t.isDate):this.isDate=!("hour"in t),t&&"timezone"in t){var n=ICAL.TimezoneService.get(t.timezone);this.zone=n||ICAL.Timezone.localTimezone}return t&&"zone"in t&&(this.zone=t.zone),this.zone||(this.zone=ICAL.Timezone.localTimezone),this._cachedUnixTime=null,this},dayOfWeek:function(t){var e=t||ICAL.Time.SUNDAY,r=(this.year<<12)+(this.month<<8)+(this.day<<3)+e;if(r in ICAL.Time._dowCache)return ICAL.Time._dowCache[r];var n=this.day,i=this.month+(this.month<3?12:0),a=this.year-(this.month<3?1:0),s=n+a+ICAL.helpers.trunc(26*(i+1)/10)+ICAL.helpers.trunc(a/4);return s=((s+=6*ICAL.helpers.trunc(a/100)+ICAL.helpers.trunc(a/400))+7-e)%7+1,ICAL.Time._dowCache[r]=s},dayOfYear:function(){var t=ICAL.Time.isLeapYear(this.year)?1:0;return ICAL.Time.daysInYearPassedMonth[t][this.month-1]+this.day},startOfWeek:function(t){var e=t||ICAL.Time.SUNDAY,r=this.clone();return r.day-=(this.dayOfWeek()+7-e)%7,r.isDate=!0,r.hour=0,r.minute=0,r.second=0,r},endOfWeek:function(t){var e=t||ICAL.Time.SUNDAY,r=this.clone();return r.day+=(7-this.dayOfWeek()+e-ICAL.Time.SUNDAY)%7,r.isDate=!0,r.hour=0,r.minute=0,r.second=0,r},startOfMonth:function(){var t=this.clone();return t.day=1,t.isDate=!0,t.hour=0,t.minute=0,t.second=0,t},endOfMonth:function(){var t=this.clone();return t.day=ICAL.Time.daysInMonth(t.month,t.year),t.isDate=!0,t.hour=0,t.minute=0,t.second=0,t},startOfYear:function(){var t=this.clone();return t.day=1,t.month=1,t.isDate=!0,t.hour=0,t.minute=0,t.second=0,t},endOfYear:function(){var t=this.clone();return t.day=31,t.month=12,t.isDate=!0,t.hour=0,t.minute=0,t.second=0,t},startDoyWeek:function(t){var e=t||ICAL.Time.SUNDAY,r=this.dayOfWeek()-e;return r<0&&(r+=7),this.dayOfYear()-r},getDominicalLetter:function(){return ICAL.Time.getDominicalLetter(this.year)},nthWeekDay:function(t,e){var r,n=ICAL.Time.daysInMonth(this.month,this.year),i=e,a=0,s=this.clone();if(0<=i){s.day=1,0!=i&&i--,a=s.day;var o=t-s.dayOfWeek();o<0&&(o+=7),a+=o,a-=t,r=t}else{s.day=n,i++,(r=s.dayOfWeek()-t)<0&&(r+=7),r=n-r}return a+(r+=7*i)},isNthWeekDay:function(t,e){var r=this.dayOfWeek();return 0===e&&r===t||this.nthWeekDay(t,e)===this.day},weekNumber:function(t){var e,r=(this.year<<12)+(this.month<<8)+(this.day<<3)+t;if(r in ICAL.Time._wnCache)return ICAL.Time._wnCache[r];var n=this.clone();n.isDate=!0;var i=this.year;12==n.month&&25ICAL.Time.daysInYearPassedMonth[a][12])return a=ICAL.Time.isLeapYear(r)?1:0,n-=ICAL.Time.daysInYearPassedMonth[a][12],r++,ICAL.Time.fromDayOfYear(n,r);i.year=r,i.isDate=!0;for(var s=11;0<=s;s--)if(n>ICAL.Time.daysInYearPassedMonth[a][s]){i.month=s+1,i.day=n-ICAL.Time.daysInYearPassedMonth[a][s];break}return i.auto_normalize=!0,i},ICAL.Time.fromStringv2=function(t){return new ICAL.Time({year:parseInt(t.substr(0,4),10),month:parseInt(t.substr(5,2),10),day:parseInt(t.substr(8,2),10),isDate:!0})},ICAL.Time.fromDateString=function(t){return new ICAL.Time({year:ICAL.helpers.strictParseInt(t.substr(0,4)),month:ICAL.helpers.strictParseInt(t.substr(5,2)),day:ICAL.helpers.strictParseInt(t.substr(8,2)),isDate:!0})},ICAL.Time.fromDateTimeString=function(t,e){if(t.length<19)throw new Error('invalid date-time value: "'+t+'"');var r;return t[19]&&"Z"===t[19]?r="Z":e&&(r=e.getParameter("tzid")),new ICAL.Time({year:ICAL.helpers.strictParseInt(t.substr(0,4)),month:ICAL.helpers.strictParseInt(t.substr(5,2)),day:ICAL.helpers.strictParseInt(t.substr(8,2)),hour:ICAL.helpers.strictParseInt(t.substr(11,2)),minute:ICAL.helpers.strictParseInt(t.substr(14,2)),second:ICAL.helpers.strictParseInt(t.substr(17,2)),timezone:r})},ICAL.Time.fromString=function(t){return 10ICAL.Time.THURSDAY&&(r.day+=7),i>ICAL.Time.THURSDAY&&(r.day-=7),r.day-=n-i,r},ICAL.Time.getDominicalLetter=function(t){var e="GFEDCBA",r=(t+(t/4|0)+(t/400|0)-(t/100|0)-1)%7;return ICAL.Time.isLeapYear(t)?e[(6+r)%7]+e[r]:e[r]},ICAL.Time.epochTime=ICAL.Time.fromData({year:1970,month:1,day:1,hour:0,minute:0,second:0,isDate:!1,timezone:"Z"}),ICAL.Time._cmp_attr=function(t,e,r){return t[r]>e[r]?1:t[r] '+e);if(void 0!==r&&rs||0==this.last.day)throw new Error("Malformed values in BYDAY part")}else if(this.has_by_data("BYMONTHDAY")&&this.last.day<0){s=ICAL.Time.daysInMonth(this.last.month,this.last.year);this.last.day=s+this.last.day+1}},next:function(){var t,e=this.last?this.last.clone():null;if(this.rule.count&&this.occurrence_number>=this.rule.count||this.rule.until&&0i)){if(n<0)n=i+(n+1);else if(0===n)continue;-1===a.indexOf(n)&&a.push(n)}return a.sort(function(t,e){return t-e})},_byDayAndMonthDay:function(t){var e,r,n,i,a=this.by_data.BYDAY,s=0,o=a.length,u=0,h=this,c=this.last.day;function l(){for(i=ICAL.Time.daysInMonth(h.last.month,h.last.year),e=h.normalizeByMonthDayRules(h.last.year,h.last.month,h.by_data.BYMONTHDAY),n=e.length;e[s]<=c&&(!t||e[s]!=c)&&s=this.by_data.BYMONTHDAY.length&&(this.by_indices.BYMONTHDAY=0,this.increment_month());e=ICAL.Time.daysInMonth(this.last.month,this.last.year);(a=this.by_data.BYMONTHDAY[this.by_indices.BYMONTHDAY])<0&&(a=e+a+1),ee?t=0:this.last.day=this.by_data.BYMONTHDAY[0]}return t},next_weekday_by_week:function(){var t=0;if(0==this.next_hour())return t;if(!this.has_by_data("BYDAY"))return 1;for(;;){var e=new ICAL.Time;this.by_indices.BYDAY++,this.by_indices.BYDAY==Object.keys(this.by_data.BYDAY).length&&(this.by_indices.BYDAY=0,t=1);var r=this.by_data.BYDAY[this.by_indices.BYDAY],n=this.ruleDayOfWeek(r)[1];(n-=this.rule.wkst)<0&&(n+=7),e.year=this.last.year,e.month=this.last.month,e.day=this.last.day;var i=e.startDoyWeek(this.rule.wkst);if(!(n+i<1)||t){var a=ICAL.Time.fromDayOfYear(i+n,this.last.year);return this.last.year=a.year,this.last.month=a.month,this.last.day=a.day,t}}},next_year:function(){if(0==this.next_hour())return 0;if(++this.days_index==this.days.length)for(this.days_index=0;this.increment_year(this.rule.interval),this.expand_year_days(this.last.year),0==this.days.length;);return this._nextByYearDay(),1},_nextByYearDay:function(){var t=this.days[this.days_index],e=this.last.year;t<1&&(t+=1,e+=1);var r=ICAL.Time.fromDayOfYear(t,e);this.last.day=r.day,this.last.month=r.month},ruleDayOfWeek:function(t,e){var r=t.match(/([+-]?[0-9])?(MO|TU|WE|TH|FR|SA|SU)/);return r?[parseInt(r[1]||0,10),t=ICAL.Recur.icalDayToNumericDay(r[2],e)]:[0,0]},next_generic:function(t,e,r,n,i){var a=t in this.by_data,s=this.rule.freq==e,o=0;if(i&&0==this[i]())return o;if(a){this.by_indices[t]++;this.by_indices[t];var u=this.by_data[t];this.by_indices[t]==u.length&&(this.by_indices[t]=0,o=1),this.last[r]=u[this.by_indices[t]]}else s&&this["increment_"+r](this.rule.interval);return a&&o&&s&&this["increment_"+n](1),o},increment_monthday:function(t){for(var e=0;er&&(this.last.day-=r,this.increment_month())}},increment_month:function(){if(this.last.day=1,this.has_by_data("BYMONTH"))this.by_indices.BYMONTH++,this.by_indices.BYMONTH==this.by_data.BYMONTH.length&&(this.by_indices.BYMONTH=0,this.increment_year(1)),this.last.month=this.by_data.BYMONTH[this.by_indices.BYMONTH];else{"MONTHLY"==this.rule.freq?this.last.month+=this.rule.interval:this.last.month++,this.last.month--;var t=ICAL.helpers.trunc(this.last.month/12);this.last.month%=12,this.last.month++,0!=t&&this.increment_year(t)}},increment_year:function(t){this.last.year+=t},increment_generic:function(t,e,r,n){this.last[e]+=t;var i=ICAL.helpers.trunc(this.last[e]/r);this.last[e]%=r,0!=i&&this["increment_"+n](i)},has_by_data:function(t){return t in this.rule.parts},expand_year_days:function(t){var e=new ICAL.Time;this.days=[];var r={},n=["BYDAY","BYWEEKNO","BYMONTHDAY","BYMONTH","BYYEARDAY"];for(var i in n)if(n.hasOwnProperty(i)){var a=n[i];a in this.rule.parts&&(r[a]=this.rule.parts[a])}if("BYMONTH"in r&&"BYWEEKNO"in r){var s=1,o={};e.year=t,e.isDate=!0;for(var u=0;ue[0]?1:e[0]>t[0]?-1:0}return t.prototype={THISANDFUTURE:"THISANDFUTURE",exceptions:null,strictExceptions:!1,relateException:function(t){if(this.isRecurrenceException())throw new Error("cannot relate exception to exceptions");if(t instanceof ICAL.Component&&(t=new ICAL.Event(t)),this.strictExceptions&&t.uid!==this.uid)throw new Error("attempted to relate unrelated exception");var e=t.recurrenceId.toString();if((this.exceptions[e]=t).modifiesFuture()){var r=[t.recurrenceId.toUnixTime(),e],n=ICAL.helpers.binsearchInsert(this.rangeExceptions,r,i);this.rangeExceptions.splice(n,0,r)}},modifiesFuture:function(){return!!this.component.hasProperty("recurrence-id")&&this.component.getFirstProperty("recurrence-id").getParameter("range")===this.THISANDFUTURE},findRangeException:function(t){if(!this.rangeExceptions.length)return null;var e=t.toUnixTime(),r=ICAL.helpers.binsearchInsert(this.rangeExceptions,[e],i);if(--r<0)return null;var n=this.rangeExceptions[r];return e 7) { + dow -= 7; + } + return REVERSE_DOW_MAP[dow]; }; var VALID_DAY_NAMES = /^(SU|MO|TU|WE|TH|FR|SA)$/; diff --git a/lib/ical/recur_iterator.js b/lib/ical/recur_iterator.js index 62a230e8..4c76c4c3 100644 --- a/lib/ical/recur_iterator.js +++ b/lib/ical/recur_iterator.js @@ -176,7 +176,7 @@ ICAL.RecurIterator = (function() { if ("BYDAY" in parts) { // libical does this earlier when the rule is loaded, but we postpone to // now so we can preserve the original order. - this.sort_byday_rules(parts.BYDAY, this.rule.wkst); + this.sort_byday_rules(parts.BYDAY); } // If the BYYEARDAY appares, no other date rule part may appear @@ -219,11 +219,11 @@ ICAL.RecurIterator = (function() { if (this.rule.freq == "WEEKLY") { if ("BYDAY" in parts) { - var bydayParts = this.ruleDayOfWeek(parts.BYDAY[0]); + var bydayParts = this.ruleDayOfWeek(parts.BYDAY[0], this.rule.wkst); var pos = bydayParts[0]; var dow = bydayParts[1]; - var wkdy = dow - this.last.dayOfWeek(); - if ((this.last.dayOfWeek() < dow && wkdy >= 0) || wkdy < 0) { + var wkdy = dow - this.last.dayOfWeek(this.rule.wkst); + if ((this.last.dayOfWeek(this.rule.wkst) < dow && wkdy >= 0) || wkdy < 0) { // Initial time is after first day of BYDAY data this.last.day += wkdy; } @@ -843,11 +843,16 @@ ICAL.RecurIterator = (function() { this.last.month = next.month; }, - ruleDayOfWeek: function ruleDayOfWeek(dow) { + /** + * @param dow (eg: '1TU', '-1MO') + * @param {ICAL.Time.weekDay=} aWeekStart The week start weekday + * @return [pos, numericDow] (eg: [1, 3]) numericDow is relative to aWeekStart + */ + ruleDayOfWeek: function ruleDayOfWeek(dow, aWeekStart) { var matches = dow.match(/([+-]?[0-9])?(MO|TU|WE|TH|FR|SA|SU)/); if (matches) { var pos = parseInt(matches[1] || 0, 10); - dow = ICAL.Recur.icalDayToNumericDay(matches[2]); + dow = ICAL.Recur.icalDayToNumericDay(matches[2], aWeekStart); return [pos, dow]; } else { return [0, 0]; @@ -1300,15 +1305,11 @@ ICAL.RecurIterator = (function() { return false; }, - sort_byday_rules: function icalrecur_sort_byday_rules(aRules, aWeekStart) { + sort_byday_rules: function icalrecur_sort_byday_rules(aRules) { for (var i = 0; i < aRules.length; i++) { for (var j = 0; j < i; j++) { - var one = this.ruleDayOfWeek(aRules[j])[1]; - var two = this.ruleDayOfWeek(aRules[i])[1]; - one -= aWeekStart; - two -= aWeekStart; - if (one < 0) one += 7; - if (two < 0) two += 7; + var one = this.ruleDayOfWeek(aRules[j], this.rule.wkst)[1]; + var two = this.ruleDayOfWeek(aRules[i], this.rule.wkst)[1]; if (one > two) { var tmp = aRules[i]; diff --git a/lib/ical/time.js b/lib/ical/time.js index 073c1d36..4ccaeee8 100644 --- a/lib/ical/time.js +++ b/lib/ical/time.js @@ -225,10 +225,13 @@ /** * Calculate the day of week. + * @param {ICAL.Time.weekDay=} aWeekStart + * The week start weekday, defaults to SUNDAY * @return {ICAL.Time.weekDay} */ - dayOfWeek: function icaltime_dayOfWeek() { - var dowCacheKey = (this.year << 9) + (this.month << 5) + this.day; + dayOfWeek: function icaltime_dayOfWeek(aWeekStart) { + var firstDow = aWeekStart || ICAL.Time.SUNDAY; + var dowCacheKey = (this.year << 12) + (this.month << 8) + (this.day << 3) + firstDow; if (dowCacheKey in ICAL.Time._dowCache) { return ICAL.Time._dowCache[dowCacheKey]; } @@ -246,8 +249,8 @@ h += 5; } - // Normalize to 1 = sunday - h = ((h + 6) % 7) + 1; + // Normalize to 1 = wkst + h = ((h + 7 - firstDow) % 7) + 1; ICAL.Time._dowCache[dowCacheKey] = h; return h; }, diff --git a/test/recur_iterator_test.js b/test/recur_iterator_test.js index 46d62315..09063a37 100644 --- a/test/recur_iterator_test.js +++ b/test/recur_iterator_test.js @@ -839,6 +839,31 @@ suite('recur_iterator', function() { '2015-01-01T08:00:00' ] }); + + //Weekly Sunday, Monday, Tuesday with count=3 + testRRULE('FREQ=WEEKLY;COUNT=3;BYDAY=MO,SU,TU', { + dtStart: '2017-07-30', + byCount: true, + dates: [ + '2017-07-30', + '2017-07-31', + '2017-08-01' + ] + }); + + //Weekly Sunday, Wednesday with count=5 + testRRULE('FREQ=WEEKLY;COUNT=5;BYDAY=SU,WE', { + dtStart: '2017-04-23', + byCount: true, + dates: [ + '2017-04-23', + '2017-04-26', + '2017-04-30', + '2017-05-03', + '2017-05-07' + ] + }); + //yearly, byMonth, byweekNo /* TODO BYWEEKNO is not well supported testRRULE('FREQ=YEARLY;BYMONTH=6,9;BYWEEKNO=23', { diff --git a/test/recur_test.js b/test/recur_test.js index 9149fe38..9a426be7 100644 --- a/test/recur_test.js +++ b/test/recur_test.js @@ -552,6 +552,70 @@ suite('recur', function() { }); }(map)); } + + var expectedWithWkst = [ + //day, wkst, expected + ['SU', Time.SUNDAY, 1], + ['MO', Time.SUNDAY, 2], + ['TU', Time.SUNDAY, 3], + ['WE', Time.SUNDAY, 4], + ['TH', Time.SUNDAY, 5], + ['FR', Time.SUNDAY, 6], + ['SA', Time.SUNDAY, 7], + ['SU', Time.MONDAY, 7], + ['MO', Time.MONDAY, 1], + ['TU', Time.MONDAY, 2], + ['WE', Time.MONDAY, 3], + ['TH', Time.MONDAY, 4], + ['FR', Time.MONDAY, 5], + ['SA', Time.MONDAY, 6], + ['SU', Time.TUESDAY, 6], + ['MO', Time.TUESDAY, 7], + ['TU', Time.TUESDAY, 1], + ['WE', Time.TUESDAY, 2], + ['TH', Time.TUESDAY, 3], + ['FR', Time.TUESDAY, 4], + ['SA', Time.TUESDAY, 5], + ['SU', Time.WEDNESDAY, 5], + ['MO', Time.WEDNESDAY, 6], + ['TU', Time.WEDNESDAY, 7], + ['WE', Time.WEDNESDAY, 1], + ['TH', Time.WEDNESDAY, 2], + ['FR', Time.WEDNESDAY, 3], + ['SA', Time.WEDNESDAY, 4], + ['SU', Time.THURSDAY, 4], + ['MO', Time.THURSDAY, 5], + ['TU', Time.THURSDAY, 6], + ['WE', Time.THURSDAY, 7], + ['TH', Time.THURSDAY, 1], + ['FR', Time.THURSDAY, 2], + ['SA', Time.THURSDAY, 3], + ['SU', Time.FRIDAY, 3], + ['MO', Time.FRIDAY, 4], + ['TU', Time.FRIDAY, 5], + ['WE', Time.FRIDAY, 6], + ['TH', Time.FRIDAY, 7], + ['FR', Time.FRIDAY, 1], + ['SA', Time.FRIDAY, 2], + ['SU', Time.SATURDAY, 2], + ['MO', Time.SATURDAY, 3], + ['TU', Time.SATURDAY, 4], + ['WE', Time.SATURDAY, 5], + ['TH', Time.SATURDAY, 6], + ['FR', Time.SATURDAY, 7], + ['SA', Time.SATURDAY, 1] + ]; + + for (var i = 0; i< expectedWithWkst.length; i++) { + (function(list) { + test(list[0] + ' to constant, wkst = ' + list[1], function() { + assert.equal( + ICAL.Recur.icalDayToNumericDay(list[0], list[1]), + list[2] + ); + }); + }(expectedWithWkst[i])); + } }); suite('ICAL.Recur#numericDayToIcalDay', function() { @@ -568,7 +632,7 @@ suite('recur', function() { (function(map) { test(map + ' to ' + expected[map], function() { assert.equal( - ICAL.Recur.numericDayToIcalDay(map), + ICAL.Recur.numericDayToIcalDay(+map), expected[map] ); }); @@ -576,4 +640,67 @@ suite('recur', function() { } }); + var expectedWithWkst = [ + //expectedDay, wkst, numericDay + ['SU', Time.SUNDAY, 1], + ['MO', Time.SUNDAY, 2], + ['TU', Time.SUNDAY, 3], + ['WE', Time.SUNDAY, 4], + ['TH', Time.SUNDAY, 5], + ['FR', Time.SUNDAY, 6], + ['SA', Time.SUNDAY, 7], + ['SU', Time.MONDAY, 7], + ['MO', Time.MONDAY, 1], + ['TU', Time.MONDAY, 2], + ['WE', Time.MONDAY, 3], + ['TH', Time.MONDAY, 4], + ['FR', Time.MONDAY, 5], + ['SA', Time.MONDAY, 6], + ['SU', Time.TUESDAY, 6], + ['MO', Time.TUESDAY, 7], + ['TU', Time.TUESDAY, 1], + ['WE', Time.TUESDAY, 2], + ['TH', Time.TUESDAY, 3], + ['FR', Time.TUESDAY, 4], + ['SA', Time.TUESDAY, 5], + ['SU', Time.WEDNESDAY, 5], + ['MO', Time.WEDNESDAY, 6], + ['TU', Time.WEDNESDAY, 7], + ['WE', Time.WEDNESDAY, 1], + ['TH', Time.WEDNESDAY, 2], + ['FR', Time.WEDNESDAY, 3], + ['SA', Time.WEDNESDAY, 4], + ['SU', Time.THURSDAY, 4], + ['MO', Time.THURSDAY, 5], + ['TU', Time.THURSDAY, 6], + ['WE', Time.THURSDAY, 7], + ['TH', Time.THURSDAY, 1], + ['FR', Time.THURSDAY, 2], + ['SA', Time.THURSDAY, 3], + ['SU', Time.FRIDAY, 3], + ['MO', Time.FRIDAY, 4], + ['TU', Time.FRIDAY, 5], + ['WE', Time.FRIDAY, 6], + ['TH', Time.FRIDAY, 7], + ['FR', Time.FRIDAY, 1], + ['SA', Time.FRIDAY, 2], + ['SU', Time.SATURDAY, 2], + ['MO', Time.SATURDAY, 3], + ['TU', Time.SATURDAY, 4], + ['WE', Time.SATURDAY, 5], + ['TH', Time.SATURDAY, 6], + ['FR', Time.SATURDAY, 7], + ['SA', Time.SATURDAY, 1] + ]; + + for (var i = 0; i< expectedWithWkst.length; i++) { + (function(list) { + test(list[2] + ' to string, wkst = ' + list[1], function() { + assert.equal( + ICAL.Recur.numericDayToIcalDay(list[2], list[1]), + list[0] + ); + }); + }(expectedWithWkst[i])); + } }); diff --git a/test/time_test.js b/test/time_test.js index b91a92a8..bdfa0cf1 100644 --- a/test/time_test.js +++ b/test/time_test.js @@ -405,6 +405,77 @@ suite('icaltime', function() { }); }); + var assertionsWithWkst = [ + //wkst, expectedDayofWeek, date + [Time.SUNDAY, 1, new Date(2012, 0, 1)], + [Time.SUNDAY, 2, new Date(2012, 0, 2)], + [Time.SUNDAY, 3, new Date(2012, 0, 3)], + [Time.SUNDAY, 4, new Date(2012, 0, 4)], + [Time.SUNDAY, 5, new Date(2012, 0, 5)], + [Time.SUNDAY, 6, new Date(2012, 0, 6)], + [Time.SUNDAY, 7, new Date(2012, 0, 7)], + [Time.MONDAY, 7, new Date(2012, 0, 1)], + [Time.MONDAY, 1, new Date(2012, 0, 2)], + [Time.MONDAY, 2, new Date(2012, 0, 3)], + [Time.MONDAY, 3, new Date(2012, 0, 4)], + [Time.MONDAY, 4, new Date(2012, 0, 5)], + [Time.MONDAY, 5, new Date(2012, 0, 6)], + [Time.MONDAY, 6, new Date(2012, 0, 7)], + [Time.TUESDAY, 6, new Date(2012, 0, 1)], + [Time.TUESDAY, 7, new Date(2012, 0, 2)], + [Time.TUESDAY, 1, new Date(2012, 0, 3)], + [Time.TUESDAY, 2, new Date(2012, 0, 4)], + [Time.TUESDAY, 3, new Date(2012, 0, 5)], + [Time.TUESDAY, 4, new Date(2012, 0, 6)], + [Time.TUESDAY, 5, new Date(2012, 0, 7)], + [Time.WEDNESDAY, 5, new Date(2012, 0, 1)], + [Time.WEDNESDAY, 6, new Date(2012, 0, 2)], + [Time.WEDNESDAY, 7, new Date(2012, 0, 3)], + [Time.WEDNESDAY, 1, new Date(2012, 0, 4)], + [Time.WEDNESDAY, 2, new Date(2012, 0, 5)], + [Time.WEDNESDAY, 3, new Date(2012, 0, 6)], + [Time.WEDNESDAY, 4, new Date(2012, 0, 7)], + [Time.THURSDAY, 4, new Date(2012, 0, 1)], + [Time.THURSDAY, 5, new Date(2012, 0, 2)], + [Time.THURSDAY, 6, new Date(2012, 0, 3)], + [Time.THURSDAY, 7, new Date(2012, 0, 4)], + [Time.THURSDAY, 1, new Date(2012, 0, 5)], + [Time.THURSDAY, 2, new Date(2012, 0, 6)], + [Time.THURSDAY, 3, new Date(2012, 0, 7)], + [Time.FRIDAY, 3, new Date(2012, 0, 1)], + [Time.FRIDAY, 4, new Date(2012, 0, 2)], + [Time.FRIDAY, 5, new Date(2012, 0, 3)], + [Time.FRIDAY, 6, new Date(2012, 0, 4)], + [Time.FRIDAY, 7, new Date(2012, 0, 5)], + [Time.FRIDAY, 1, new Date(2012, 0, 6)], + [Time.FRIDAY, 2, new Date(2012, 0, 7)], + [Time.SATURDAY, 2, new Date(2012, 0, 1)], + [Time.SATURDAY, 3, new Date(2012, 0, 2)], + [Time.SATURDAY, 4, new Date(2012, 0, 3)], + [Time.SATURDAY, 5, new Date(2012, 0, 4)], + [Time.SATURDAY, 6, new Date(2012, 0, 5)], + [Time.SATURDAY, 7, new Date(2012, 0, 6)], + [Time.SATURDAY, 1, new Date(2012, 0, 7)] + ]; + + assertionsWithWkst.forEach(function(item) { + var wkst = item[0]; + var dayOfWeek = item[1]; + var date = item[2]; + var human = date.getFullYear() + '-' + date.getMonth() + '-' + date.getDate(); + var msg = human + ' should be #' + dayOfWeek + ' day'; + + test(msg, function() { + var subject = new ICAL.Time.fromJSDate( + date + ); + + assert.equal( + subject.dayOfWeek(wkst), + dayOfWeek + ); + }); + }); }); suite('#dayOfYear', function() {