'Get a list of Sundays for next three months

I need to get a list of Sundays for the next three months. I wrote a function which worked up until today. Three months from today is January, which is 0 so my for loop doesn't work.

function getSundays(year) {
  const offdays = [];
  let i = -1;
  const currentDate = new Date();
  currentDate.setDate(currentDate.getDate() + 90);
  for ( let month = new Date().getMonth(); month < currentDate.getMonth(); month += 1) {
    const tdays = new Date(year, month, 0).getDate();
    for (let date = 1; date <= tdays; date += 1) {
      const smonth = (month < 9) ? `0${month + 1}` : month + 1;
      const sdate = (date < 10) ? `0${date}` : date;
      const dd = `${year}-${smonth}-${sdate}`;
      const day = new Date();
      day.setDate(date);
      day.setMonth(month);
      day.setFullYear(year);
      if (day.getDay()  ===  0 ) {
        offdays[i += 1] = dd;
      }
    }
  }
  return offdays;
}

How can I get around this?



Solution 1:[1]

Assuming there are about 4 Sundays per month.

function getSundays() {
    const sundays = [];

    var sunday = new Date()
    sunday.setDate(sunday.getDate() + 7 - sunday.getDay());

    for (var i = 0; i < 12; i++) {
        console.log(sunday.toLocaleString());
        sundays.push(new Date(sunday.getTime()));
        sunday.setDate(sunday.getDate() + 7);
    }

    return sundays;
}

getSundays();

Solution 2:[2]

Please test code below.

var startDate = new Date(2018, 0, 1);
var endDate = new Date(2018,11, 31);
var day = 0;  
for (i = 0; i <= 7; i++) { 
    if(startDate.toString().indexOf('Sun') !== -1){
       break;
    }
    startDate =  new Date(2018, 0, i);
}

var result = [];
startDate = moment(startDate);
endDate = moment(endDate);
var current = startDate.clone();
while (current.day(7 + day).isBefore(endDate)) {
  result.push(current.clone());
}

//console.log(result.map(m => m.format('LLLL')));
console.log(result.map(m => m.format('YYYY-MM-DD')));
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment.min.js"></script>

Solution 3:[3]

If you wanted a non-momentjs based approach, perhaps you could do something like this?

This method increments one day at a time, continuing three months into the future and looks for any date instances where getDay() === 0 (ie Sunday).

The increment is done via milliseconds as a convenient way to create date objects for specific day/month/years. The month counter tracks changes in the month/year between the currentDate and nextDate to determine if the month counter should be incremented:

function getSundays(year) {
  
  var start = new Date();
  start.setYear(year);
  var startEpoch = start.valueOf();
  
  var dayDuration = 86400000; // Milliseconds in a day
  var currentEpoch = startEpoch;
  
  var offdays = [];
  
  // Iterate over three month period from as required
  for(var monthCounter = 0; monthCounter < 3; ) {
  	
    var currentDate = new Date(currentEpoch);
    var nextDate = new Date(currentEpoch + dayDuration);
    
    // If the next month or next year has increased from 
    // current month or year, then increment the month counter
    if(nextDate.getMonth() > currentDate.getMonth() || 
    nextDate.getYear() > currentDate.getYear()) {
    	monthCounter ++;
    }
  	
    if(currentDate.getDay() === 0) {
    	offdays.push(currentDate);
    }
    
    currentEpoch += dayDuration;
  	
  }
  
  return offdays;
}

console.log(getSundays(2018).map(date => date.toString()));

Solution 4:[4]

You can make using methods of Date get|setMonth and get|setDay, like a make this:

const next = new Date()
next.setMonth( (new Date()).getMonth()+1 )

const allSundays = []
const sundaysByMonth = []

for( let i = 0; i<3; i++ ){

    const m = next.getMonth()
    
    const sundays = []
    for( let j = 0; j < 7; j++ ){
    	
    	if ( next.getDay() == 0 ){
            sundays.push( next.getDate() )
            allSundays.push( next.getDate() )
            next.setDate( next.getDate() + 6 )  // increment in 6 days not 7 (one week) because line below increase again
        }
        
        next.setDate( next.getDate() + 1 ) // increase month day until arrive in sunday
        if( next.getMonth() != m ){ // check if not exceeded the month
        	sundaysByMonth.push( sundays )
          	break // break to go to next month
        }
        
    }
}

console.log( allSundays )
console.log( sundaysByMonth )
const el = document.getElementById("demo");

for( let i = 0; i < allSundays.length; i++ ){
  const li = document.createElement('li')
  li.innerHTML = 'Sunday '+ allSundays[i]+' '
  el.appendChild(li)
}
<p>The getDay() method returns the weekday as a number:</p>

<ul id="demo"></ul>

Solution 5:[5]

Looked at some of the answers already given and they seemed close and inspired me to give a shot without using moment.js - Commented pretty heavily, hopefully explains it, but it works for my understanding of the problem, although you probably need to shape the result value for your purposes, but it contains what you need, I believe.

function getSundaysForNextCalendarMonths(numberOfMonths, dateVal){
	let trackingObj = {};  // We'll use this object to track our trackingObjs by month in our loop.
	let result = []; // We'll just push the date from each iteration here rather than make a mapping function on the result for this example.  might be overkill anyways, this array shouldn't contain more than 15 days
	if(!dateVal){
		dateVal = new Date(); // initialize the date to today or wherever you want to start from
	}
	// Using today's date as reference the first time through the loop we find out how far off Sunday it is, and then add the difference times the time of day in milliseconds in UNIX time
	// but first - we'll also set the time to 2 AM to work around any potential daylight savings time weirdness in case the hour shifts up or down over a the period
	dateVal.setHours(2);
	dateVal.setTime(dateVal.getTime() + (7 - dateVal.getDay()) * (24*60*60*1000)); // mutated dateVal to now equal following Sunday
	result.push(dateVal.toDateString());
	// This loop in theory will break before iterates all the way through, because you'd never have 15 Sundays in a 3 month, but I removed the while loop because it's easier to ascertain the runtime of the loop
	for(let i = 0; i < numberOfMonths * 5; i++){ 
		// we just add 7 days in milliseconds to dateVal to get next Sunday
		dateVal.setTime(dateVal.getTime() + 7 * (24*60*60*1000));
		if(trackingObj[dateVal.getMonth()]) {  // If there's already a month in the reuslt, push to the array that's there.
			result.push(dateVal.toDateString());
		} else if(!trackingObj[dateVal.getMonth()] && Object.keys(trackingObj).length < numberOfMonths){  // Otherwise if there's not too many months in  the trackingObj put the object in the array
			trackingObj[dateVal.getMonth()] = true;
			result.push(dateVal.toDateString());
		} else {
			break;  // more than 3 months break loop.  you have your trackingObj
		}
	}
	return result;
}
console.log(getSundaysForNextCalendarMonths(3));
enter code here

Solution 6:[6]

This is more general, very simple, and will work 90 or 900 days into the future

function sundaysInFuture(numDays) {
    const dt = new Date();
    const sundays = [];
    for (let i = 0; i < numDays; i++) {
      const thisDay = new Date(
        dt.getFullYear(),
        dt.getMonth(),
        dt.getDate() + i
      );
      if (thisDay.getDay() === 0) {
        sundays.push({
          dayOfMonth: thisDay.getDate(),
          iso: thisDay.toISOString(),
        });
      }
    }
    console.log(sundays);
    return sundays;
  }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3
Solution 4
Solution 5
Solution 6 Richard Lanham