Joshua
Joshua

Reputation: 33

Get date of specific weekday after a specified date with Moment.js

I am trying to get the date for the next instance of a weekday after a given date. The weekday may be any day from Monday through Sunday. I am using the Moment.js library but there doesn't seem to be a simple way to achieve what I am after.

This is what I have so far but it's not returning the date I want:

// competition.startDate = 2016-02-10 (Wednesday)
var startDate = moment(competition.startDate);

...

for (m = 0; m < matchesPerRound; m++) {
    var date;

    ...

    // matchTime[m].day = 3 (Wednesday)
    date = startDate.startOf('week').add(7, 'days').subtract(matchTime[m].day, 'days');

    console.log(date.format('YYYY-MM-DD'));
    // Actual Output = 2016-02-11
    // Expected Output = 2016-02-10
    ...

}

With the example above, I need it returning 2016-02-15 as this is the next Monday after 2016-02-10. This is no problem, and I can get that date. My problem is that I need something more dynamic, as matchTime[m].day could be any weekday number. For example, if matchTime[m].day = 3 // Wednesday, it should just return the same startDate 2016-02-10 as this is a Wednesday.

I'm trying to avoid conditional statements if possible, but I am wondering if Moment.js has the functionality out of the box to produce these results.

UPDATE

I've come up with a solution, and it's working with my requirements, but I feel it's very messy. Does someone else have a cleaner, more concise solution?

var date;
var startDate = moment(competition.startDate);
var proposedDate = moment(startDate).startOf('isoweek').add(matchTimes[0].day - 1, 'd');
if ( startDate.isAfter(proposedDate) ) {
    date = startDate.startOf('isoweek').add(7 + Number(matchTimes[0].day) - 1, 'd');
} else {
    date = startDate.startOf('isoweek').add(matchTimes[0].day - 1, 'd');
}

Upvotes: 3

Views: 1737

Answers (4)

vinjenzo
vinjenzo

Reputation: 1530

My solution

var weekDayToFind = moment().day('Monday').weekday() //change monday to searched day name
var givenDate = moment('2016-02-10') // pass the given date

var searchDate = moment(givenDate)
while (searchDate.weekday() !== weekDayToFind){ 
  searchDate.add(1, 'day'); 
}

Upvotes: 0

Balah
Balah

Reputation: 2540

Here's a possible answer too using momentjs (assumes match days will be 0 (sunday) - 6):

var startDate = moment(competition.startDate);
var matchDay = Number(matchTimes[0].day);
var daysToAdd = Math.ceil((startDate.day() - matchDay) / 7) * 7 + matchDay;
var proposedDate = moment(startDate).startOf('week').add(daysToAdd, 'd');

Upvotes: 0

Rogier Spieker
Rogier Spieker

Reputation: 4187

I don't know about moment.js, but it seems rather complex for something rather simple.

function firstMatchingDayOfWeek(day, date) {
    var delta = date.getDay() - day,
        result = new Date(date);

    if (delta) {
        result.setDate(result.getDate() + ((7 - delta) % 7));
    }

    return result;
}

I think the code is rather self-explanatory (don't we all ;-) ), but in order to clarify the steps:

  • firstMatchingDayOfWeek(day, date) > call the function specifying the day of week (0-6) and a date object
  • delta = date.getDay() - day > calculate how many days the date needs to shift in order to reach the same day of week
  • result = new Date(date) > create a new Date instance based on the input (so you get to preserve the original date)
  • result.setDate(result.getDate() + ((7 - delta) % 7)) > set the date part (day of month) to a week minus the delta, modulo a week (as delta can be negative and you want the first occurrence of the same day)

function firstMatchingDayOfWeek(day, date) {
	var delta = date.getDay() - day,
		result = new Date(date);

	if (delta) {
		result.setDate(result.getDate() + ((7 - delta) % 7));
	}

	return result;
}



//  tests
for (var i = 1; i < 28; ++i){
	var check = new Date('2016-02-' + ('00' + i).substr(-2)),
  	output = document.querySelector('#out')
    	.appendChild(document.createElement('pre')),
    log = [];

	log.push('input: ' + check);

	for (var day = 0; day <= 6; ++day) {
		var next = firstMatchingDayOfWeek(day, check);

		log.push(day + ' > ' + next);
	}
  output.innerText = log.join('\n');
}
pre {
  border: 1px solid gold;
}
<div id="out"></div>

Upvotes: 1

Rajesh
Rajesh

Reputation: 24955

This is a pure JS version:

Logic

  1. Find current day.
  2. Find days to add to get to start of next week.
  3. Get day number for the day to find date.
  4. Compute date with this date.

JSFiddle.

function claculateNextDate() {
  var date = new Date();
  var nextDay = document.getElementById("dayOfWeek").value;
  var day = date.getDay();
  
  var noOfDaysToAdd = (7 - day) + parseInt(nextDay);
  date.setDate(date.getDate() + noOfDaysToAdd);

  document.getElementById("result").innerHTML = date.toDateString();
}
<select id="dayOfWeek">
  <option value="0">Sunday</option>
  <option value="1">Monday</option>
  <option value="2">Tuesday</option>
  <option value="3">Wednesday</option>
  <option value="4">Thursday</option>
  <option value="5">Friday</option>
  <option value="6">Saturday</option>
</select>
<button onclick="claculateNextDate()">Calculate Next Date</button>

<p id="result"></p>

Upvotes: 0

Related Questions