Skip to content

Commit

Permalink
Merge pull request #28 from rmarscher/nth-weekday-of-month
Browse files Browse the repository at this point in the history
Added support for nth weekday of the month recurrences.
  • Loading branch information
bramski committed Apr 8, 2015
2 parents 6b4f7af + 27ae60c commit 1559807
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 6 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,12 @@ cal = moment.recur().every("January").monthsOfYear();
// For instance, this will match only on Valentines day
var valentines = moment.recur().every(14).daysOfMonth()
.every("Februray").monthsOfYear();

// A weekOfMonthByDay interval is available for combining with
// the daysOfWeek to achieve "nth weekday of month" recurrences.
// The following matches every 1st and 3rd Thursday of the month.
cal = moment.recur().every("Thursday").daysOfWeek()
.every([0, 2]).weeksOfMonthByDay();
```


Expand Down
57 changes: 52 additions & 5 deletions moment-recur.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,19 @@
"daysOfMonth": "date",
"daysOfWeek": "day",
"weeksOfMonth": "monthWeek",
"weeksOfMonthByDay": "monthWeekByDay",
"weeksOfYear": "weeks",
"monthsOfYear": "months"
};

// Dictionary of ranges based on measures
var ranges = {
"daysOfMonth" : { low: 1, high: 31 },
"daysOfWeek" : { low: 0, high: 6 },
"weeksOfMonth" : { low: 0, high: 4 },
"weeksOfYear" : { low: 0, high: 52 },
"monthsOfYear" : { low: 0, high: 11 }
"daysOfMonth" : { low: 1, high: 31 },
"daysOfWeek" : { low: 0, high: 6 },
"weeksOfMonth" : { low: 0, high: 4 },
"weeksOfMonthByDay" : { low: 0, high: 4 },
"weeksOfYear" : { low: 0, high: 52 },
"monthsOfYear" : { low: 0, high: 11 }
};

// Private function for cehcking the range of calendar values
Expand Down Expand Up @@ -186,6 +188,7 @@
"daysOfWeek": "calendar",
"daysOfMonth": "calendar",
"weeksOfMonth": "calendar",
"weeksOfMonthByDay": "calendar",
"weeksOfYear": "calendar",
"monthsOfYear": "calendar"
};
Expand All @@ -199,6 +202,7 @@
"daysOfWeek": "dayOfWeek",
"daysOfMonth": "dayOfMonth",
"weeksOfMonth": "weekOfMonth",
"weeksOfMonthByDay": "weekOfMonthByDay",
"weeksOfYear": "weekOfYear",
"monthsOfYear": "monthOfYear"
};
Expand Down Expand Up @@ -245,6 +249,10 @@
this.units = null;
this.measure = null;

if (rule.measure === 'weeksOfMonthByDay' && !this.hasRule('daysOfWeek')) {
throw Error("weeksOfMonthByDay must be combined with daysOfWeek");
}

// Remove existing rule based on measure
for (var i = 0; i < this.rules.length; i++) {
if (this.rules[i].measure === rule.measure) {
Expand Down Expand Up @@ -385,6 +393,9 @@
case "weekOfMonth":
return "weeksOfMonth";

case "weekOfMonthByDay":
return "weeksOfMonthByDay";

case "weekOfYear":
return "weeksOfYear";

Expand Down Expand Up @@ -590,6 +601,17 @@
}
};

// Checks if a rule has been set on the chain
Recur.prototype.hasRule = function(measure) {
var i, len;
for (i = 0, len = this.rules.length; i < len; i++) {
if (this.rules[i].measure === pluralize(measure)) {
return true;
}
}
return false;
};

// Attempts to match a date to the rules
Recur.prototype.matches = function(dateToMatch, ignoreStartEnd) {
var date = moment(dateToMatch).dateOnly();
Expand Down Expand Up @@ -690,6 +712,31 @@
return day0.diff(week0, "weeks");
};

// Plugin for calculating the occurrence of the day of the week in the month.
// Similar to `moment().monthWeek()`, the return value is zero-indexed.
// A return value of 2 means the date is the 3rd occurence of that day
// of the week in the month.
moment.fn.monthWeekByDay = function(date) {
var day, week0, day0, diff;

// date obj
day = this.clone();

// First day of the first week of the month
week0 = this.clone().startOf("month").startOf("week");

// First day of week
day0 = this.clone().startOf("week");

diff = day0.diff(week0, "weeks");

if (day.subtract(diff, "weeks").month() === this.clone().month()) {
return diff;
}

return diff - 1;
};

// Plugin for removing all time information from a given date
moment.fn.dateOnly = function() {
if (this.tz && typeof(moment.tz) == 'function' ) {
Expand Down
2 changes: 1 addition & 1 deletion moment-recur.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 1559807

Please sign in to comment.