Skip to content

Commit 1559807

Browse files
committed
Merge pull request #28 from rmarscher/nth-weekday-of-month
Added support for nth weekday of the month recurrences.
2 parents 6b4f7af + 27ae60c commit 1559807

File tree

4 files changed

+106
-6
lines changed

4 files changed

+106
-6
lines changed

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,12 @@ cal = moment.recur().every("January").monthsOfYear();
207207
// For instance, this will match only on Valentines day
208208
var valentines = moment.recur().every(14).daysOfMonth()
209209
.every("Februray").monthsOfYear();
210+
211+
// A weekOfMonthByDay interval is available for combining with
212+
// the daysOfWeek to achieve "nth weekday of month" recurrences.
213+
// The following matches every 1st and 3rd Thursday of the month.
214+
cal = moment.recur().every("Thursday").daysOfWeek()
215+
.every([0, 2]).weeksOfMonthByDay();
210216
```
211217

212218

moment-recur.js

+52-5
Original file line numberDiff line numberDiff line change
@@ -75,17 +75,19 @@
7575
"daysOfMonth": "date",
7676
"daysOfWeek": "day",
7777
"weeksOfMonth": "monthWeek",
78+
"weeksOfMonthByDay": "monthWeekByDay",
7879
"weeksOfYear": "weeks",
7980
"monthsOfYear": "months"
8081
};
8182

8283
// Dictionary of ranges based on measures
8384
var ranges = {
84-
"daysOfMonth" : { low: 1, high: 31 },
85-
"daysOfWeek" : { low: 0, high: 6 },
86-
"weeksOfMonth" : { low: 0, high: 4 },
87-
"weeksOfYear" : { low: 0, high: 52 },
88-
"monthsOfYear" : { low: 0, high: 11 }
85+
"daysOfMonth" : { low: 1, high: 31 },
86+
"daysOfWeek" : { low: 0, high: 6 },
87+
"weeksOfMonth" : { low: 0, high: 4 },
88+
"weeksOfMonthByDay" : { low: 0, high: 4 },
89+
"weeksOfYear" : { low: 0, high: 52 },
90+
"monthsOfYear" : { low: 0, high: 11 }
8991
};
9092

9193
// Private function for cehcking the range of calendar values
@@ -186,6 +188,7 @@
186188
"daysOfWeek": "calendar",
187189
"daysOfMonth": "calendar",
188190
"weeksOfMonth": "calendar",
191+
"weeksOfMonthByDay": "calendar",
189192
"weeksOfYear": "calendar",
190193
"monthsOfYear": "calendar"
191194
};
@@ -199,6 +202,7 @@
199202
"daysOfWeek": "dayOfWeek",
200203
"daysOfMonth": "dayOfMonth",
201204
"weeksOfMonth": "weekOfMonth",
205+
"weeksOfMonthByDay": "weekOfMonthByDay",
202206
"weeksOfYear": "weekOfYear",
203207
"monthsOfYear": "monthOfYear"
204208
};
@@ -245,6 +249,10 @@
245249
this.units = null;
246250
this.measure = null;
247251

252+
if (rule.measure === 'weeksOfMonthByDay' && !this.hasRule('daysOfWeek')) {
253+
throw Error("weeksOfMonthByDay must be combined with daysOfWeek");
254+
}
255+
248256
// Remove existing rule based on measure
249257
for (var i = 0; i < this.rules.length; i++) {
250258
if (this.rules[i].measure === rule.measure) {
@@ -385,6 +393,9 @@
385393
case "weekOfMonth":
386394
return "weeksOfMonth";
387395

396+
case "weekOfMonthByDay":
397+
return "weeksOfMonthByDay";
398+
388399
case "weekOfYear":
389400
return "weeksOfYear";
390401

@@ -590,6 +601,17 @@
590601
}
591602
};
592603

604+
// Checks if a rule has been set on the chain
605+
Recur.prototype.hasRule = function(measure) {
606+
var i, len;
607+
for (i = 0, len = this.rules.length; i < len; i++) {
608+
if (this.rules[i].measure === pluralize(measure)) {
609+
return true;
610+
}
611+
}
612+
return false;
613+
};
614+
593615
// Attempts to match a date to the rules
594616
Recur.prototype.matches = function(dateToMatch, ignoreStartEnd) {
595617
var date = moment(dateToMatch).dateOnly();
@@ -690,6 +712,31 @@
690712
return day0.diff(week0, "weeks");
691713
};
692714

715+
// Plugin for calculating the occurrence of the day of the week in the month.
716+
// Similar to `moment().monthWeek()`, the return value is zero-indexed.
717+
// A return value of 2 means the date is the 3rd occurence of that day
718+
// of the week in the month.
719+
moment.fn.monthWeekByDay = function(date) {
720+
var day, week0, day0, diff;
721+
722+
// date obj
723+
day = this.clone();
724+
725+
// First day of the first week of the month
726+
week0 = this.clone().startOf("month").startOf("week");
727+
728+
// First day of week
729+
day0 = this.clone().startOf("week");
730+
731+
diff = day0.diff(week0, "weeks");
732+
733+
if (day.subtract(diff, "weeks").month() === this.clone().month()) {
734+
return diff;
735+
}
736+
737+
return diff - 1;
738+
};
739+
693740
// Plugin for removing all time information from a given date
694741
moment.fn.dateOnly = function() {
695742
if (this.tz && typeof(moment.tz) == 'function' ) {

moment-recur.min.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)