From cca5518b1659c1aa462f4c812f10b7e22f51750e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Izurieta?= Date: Mon, 31 Oct 2016 09:10:50 +0100 Subject: [PATCH] Make weeksOfMonthByDay match weeks from the end of the month too --- moment-recur.js | 71 +++++++++++++++++++++---------- tests/spec/jasmine-event-recur.js | 13 ++++++ 2 files changed, 61 insertions(+), 23 deletions(-) diff --git a/moment-recur.js b/moment-recur.js index af4409c..0370176 100644 --- a/moment-recur.js +++ b/moment-recur.js @@ -75,7 +75,7 @@ "daysOfMonth": "date", "daysOfWeek": "day", "weeksOfMonth": "monthWeek", - "weeksOfMonthByDay": "monthWeekByDay", + "weeksOfMonthByDay": "monthWeeksByDay", "weeksOfYear": "week", "monthsOfYear": "month" }; @@ -85,7 +85,7 @@ "daysOfMonth" : { low: 1, high: 31 }, "daysOfWeek" : { low: 0, high: 6 }, "weeksOfMonth" : { low: 0, high: 4 }, - "weeksOfMonthByDay" : { low: 0, high: 4 }, + "weeksOfMonthByDay" : { low: -5, high: 4 }, "weeksOfYear" : { low: 0, high: 52 }, "monthsOfYear" : { low: 0, high: 11 } }; @@ -150,20 +150,28 @@ var unitType = unitTypes[measure]; // Get the unit based on the required measure of the date - var unit = date[unitType](); + var units = date[unitType](); - // If the unit is in our list, return true, else return false - if (list[unit]) { - return true; + if (units.constructor !== Array) { + units = [ units ]; } - // match on end of month days - if (unitType === 'date' && unit == date.add(1, 'months').date(0).format('D') && unit < 31) { - while (unit <= 31) { - if (list[unit]) { - return true; + for (var i = 0; i < units.length; i++) { + var unit = units[i]; + + // If the unit is in our list, return true, else return false + if (list[unit]) { + return true; + } + + // match on end of month days + if (unitType === 'date' && unit == date.add(1, 'months').date(0).format('D') && unit < 31) { + while (unit <= 31) { + if (list[unit]) { + return true; + } + unit++; } - unit++; } } @@ -706,29 +714,46 @@ return day0.diff(week0, "weeks"); }; + // Plugin for calculating the last week of the month of a date + moment.fn.lastMonthWeek = function() { + // Last day of the last week of the month (may be first week of next month) + var weekL = this.clone().endOf("month").endOf("week"); + + // Last day of week + var dayL = this.clone().endOf("week"); + + return dayL.diff(weekL, "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; + var diff = this.monthWeek(); - // date obj - day = this.clone(); + if (this.clone().subtract(diff, "weeks").month() === this.month()) { + return diff; + } - // First day of the first week of the month - week0 = this.clone().startOf("month").startOf("week"); + return diff - 1; + }; - // First day of week - day0 = this.clone().startOf("week"); + // Plugin for calculating the last occurrence of the day of the week in the month. + // A return value of -3 means the date is the 3rd occurence of that day + // of the week from the end of the month. + moment.fn.lastMonthWeekByDay = function() { + var diff = this.lastMonthWeek(); - diff = day0.diff(week0, "weeks"); + if (this.clone().subtract(diff, "weeks").month() === this.month()) { + return diff - 1; + } - if (day.subtract(diff, "weeks").month() === this.clone().month()) { return diff; - } + }; - return diff - 1; + moment.fn.monthWeeksByDay = function() { + return [ this.monthWeekByDay(), this.lastMonthWeekByDay() ]; }; // Plugin for removing all time information from a given date diff --git a/tests/spec/jasmine-event-recur.js b/tests/spec/jasmine-event-recur.js index 9a2b73a..a2eb4c0 100755 --- a/tests/spec/jasmine-event-recur.js +++ b/tests/spec/jasmine-event-recur.js @@ -284,6 +284,19 @@ describe("weeksOfMonthByDay()", function() { expect(recurrence.matches(moment(startDate).date(31))).toBe(true); }); + it("can recur on the last and 3rd last Sundays of the month", function() { + var recurrence; + recurrence = moment.recur() + .every(["Sunday"]).daysOfWeek() + .every([-1, -3]).weeksOfMonthByDay(); + expect(recurrence.matches(moment(startDate))).toBe(false); + expect(recurrence.matches(moment(startDate).date(6))).toBe(false); + expect(recurrence.matches(moment(startDate).date(8))).toBe(false); + expect(recurrence.matches(moment(startDate).date(13))).toBe(true); + expect(recurrence.matches(moment(startDate).date(20))).toBe(false); + expect(recurrence.matches(moment(startDate).date(27))).toBe(true); + }); + it("will throw an error if used without daysOfWeek()", function() { var recurrence, caught = { message: false }; try {