'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 |