183

Given two Date() objects, where one is less than the other, how do I loop every day between the dates?

for(loopDate = startDate; loopDate < endDate; loopDate += 1)
{

}

Would this sort of loop work? But how can I add one day to the loop counter?

Thanks!

ashleedawg
  • 20,365
  • 9
  • 72
  • 105
Tom Gullen
  • 61,249
  • 84
  • 283
  • 456

12 Answers12

292

Here's a way to do it by making use of the way adding one day causes the date to roll over to the next month if necessary, and without messing around with milliseconds. Daylight savings aren't an issue either.

var now = new Date();
var daysOfYear = [];
for (var d = new Date(2012, 0, 1); d <= now; d.setDate(d.getDate() + 1)) {
    daysOfYear.push(new Date(d));
}

Note that if you want to store the date, you'll need to make a new one (as above with new Date(d)), or else you'll end up with every stored date being the final value of d in the loop.

David Johnstone
  • 24,300
  • 14
  • 68
  • 71
  • 1
    So much more readable than all the other answers. Adding 86400000 miliseconds each loop is not very readable. – Owen Feb 14 '13 at 12:13
  • 6
    Be careful with daylight saving times. d.getDate() + 1 when d.getDate() = GMT N and d.getDate() + 1 = GMT N - 1 d.getDate() + 1 returns the same day of month twice. – Rafael Fontes Nov 04 '13 at 13:29
  • 1
    Why do `Date.now()` when defining `now`? `new Date()` [returns the current date as an object by default](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date). Calling `Date` without the `new` constructor just gives you a Date string which you then convert to a Date object anyway? – tatlar Sep 10 '14 at 17:52
  • For me `new Date(2012, 0, 1);` was picking up the incorrect day (one day before), `new Date(Date.UTC(2012, 0, 1))` worked fine. – Tk421 Dec 29 '16 at 01:01
  • I have tried multiple solutions on the internet. Weird is that it skips sometimes some days. Like 1.12, 2.12, 3.12, 5.12... (notice that 4.12 is skipped) i have no idea why it happens... Anyone got this problem and found a solution? – Erik Kubica Jul 23 '17 at 19:54
  • If i generate full year from 1.1 to 31.12 it works fine, if i generate custom date range, it's skipping same dates – Erik Kubica Jul 24 '17 at 06:23
  • 1
    ``` d = new Date('2019-03-31') d.setDate(d.getDate() + 1) d.toISOString().slice(0, 10) // 2019-03-31 ``` ^^ fail. – Mirek Rusin Feb 22 '20 at 15:12
  • @MirekRusin That's because toISOString disregards the local time zone setting and prints the date as it would be on the UTC time zone. See https://stackoverflow.com/a/17415677/3070613 – loop Sep 30 '21 at 10:43
  • Can anyone show an example of how this one breaks with daylight saving time? – Nikowhy Oct 12 '21 at 13:16
93

Based on Tom Gullen´s answer.

var start = new Date("02/05/2013");
var end = new Date("02/10/2013");


var loop = new Date(start);
while(loop <= end){
   alert(loop);           

   var newDate = loop.setDate(loop.getDate() + 1);
   loop = new Date(newDate);
}
Community
  • 1
  • 1
Tabares
  • 4,083
  • 5
  • 40
  • 47
  • 3
    @DevAllanPer nothing, `Date` is a global object https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date – Dmitri Pisarev Jan 05 '19 at 07:24
  • ```loop = new Date(newDate);``` is not needed. You already set loop with ```loop.setDate(loop.getDate() + 1);``` – Jan Feb 14 '22 at 19:37
16

I think I found an even simpler answer, if you allow yourself to use Moment.js:

// cycle through last five days, today included
// you could also cycle through any dates you want, mostly for
// making this snippet not time aware
const currentMoment = moment().subtract(4, 'days');
const endMoment = moment().add(1, 'days');
while (currentMoment.isBefore(endMoment, 'day')) {
  console.log(`Loop at ${currentMoment.format('YYYY-MM-DD')}`);
  currentMoment.add(1, 'days');
}
<script src="https://cdn.jsdelivr.net/npm/moment@2/moment.min.js"></script>
vvo
  • 2,653
  • 23
  • 30
12

Here simple working code, worked for me

var from = new Date(2012,0,1);
var to = new Date(2012,1,20);
    
// loop for every day
for (var day = from; day <= to; day.setDate(day.getDate() + 1)) {
   // your day is here
   console.log(day)
}
WasiF
  • 26,101
  • 16
  • 120
  • 128
Amr Ibrahim
  • 2,066
  • 2
  • 23
  • 47
11

If startDate and endDate are indeed date objects you could convert them to number of milliseconds since midnight Jan 1, 1970, like this:

var startTime = startDate.getTime(), endTime = endDate.getTime();

Then you could loop from one to another incrementing loopTime by 86400000 (1000*60*60*24) - number of milliseconds in one day:

for(loopTime = startTime; loopTime < endTime; loopTime += 86400000)
{
    var loopDay=new Date(loopTime)
    //use loopDay as you wish
}
Guillaume Gendre
  • 2,504
  • 28
  • 17
jayarjo
  • 16,124
  • 24
  • 94
  • 138
  • 1
    +1, gave me enough to work on, ive included the working solution in my question – Tom Gullen Dec 03 '10 at 11:46
  • 5
    this does not work when looping past a daylight savings time change (in areas where that is an issue). Good solution otherwise. – chadgh Nov 08 '11 at 17:14
  • 4
    You can't assume there are `86400000` seconds in a day. This loop is fragile to daylight savings changes and other edge conditions. – Jeremy J Starcher Sep 30 '12 at 20:25
  • 2
    Besides DST, another edge condition is "Leap Second". A one second difference *does* matter - Dates converted to milliseconds correspond to first second of a given day. One second error and you land on previous day. – Wojtek Kruszewski May 27 '13 at 08:56
3
var start = new Date("2014-05-01"); //yyyy-mm-dd
var end = new Date("2014-05-05"); //yyyy-mm-dd

while(start <= end){

    var mm = ((start.getMonth()+1)>=10)?(start.getMonth()+1):'0'+(start.getMonth()+1);
    var dd = ((start.getDate())>=10)? (start.getDate()) : '0' + (start.getDate());
    var yyyy = start.getFullYear();
    var date = dd+"/"+mm+"/"+yyyy; //yyyy-mm-dd

    alert(date); 

    start = new Date(start.setDate(start.getDate() + 1)); //date increase by 1
}
MD SHAHIDUL ISLAM
  • 14,325
  • 6
  • 82
  • 89
2

As a function,

function getDatesFromDateRange(from, to) {
  const dates = [];
  for (let date = from; date <= to; date.setDate(date.getDate() + 1)) {
    const cloned = new Date(date.valueOf());
    dates.push(cloned);
  }
  return dates;
}

const start = new Date(2019, 11, 31);
const end = new Date(2020, 1, 1);

const datesArray = getDatesFromDateRange(start, end);
console.dir(datesArray);
naveen
  • 53,448
  • 46
  • 161
  • 251
1

Based on Tabare's Answer, I had to add one more day at the end, since the cycle is cut before

var start = new Date("02/05/2013");
var end = new Date("02/10/2013");
var newend = end.setDate(end.getDate()+1);
var end = new Date(newend);
while(start < end){
   alert(start);           

   var newDate = start.setDate(start.getDate() + 1);
   start = new Date(newDate);
}
1

Didn't want to store the result in an array, so maybe using yield?

/**
 * @param {object} params
 * @param {Date} params.from
 * @param {Date} params.to
 * @param {number | undefined} params.incrementBy
 * @yields {Date}
 */
 function* iterateDate(params) {
    const increaseBy = Math.abs(params.incrementBy ?? 1);
    for(let current = params.from; current.getTime() <= params.to.getTime(); current.setDate(current.getDate() + increaseBy)) {
        yield new Date(current);
    }
}

for (const d of iterateDate({from: new Date(2021,0,1), to: new Date(2021,0,31), incrementBy: 1})) {
    console.log(d.toISOString());
}
Alex Nolasco
  • 18,750
  • 9
  • 86
  • 81
0

If you want an efficient way with milliseconds:

var daysOfYear = [];
for (var d = begin; d <= end; d = d + 86400000) {
    daysOfYear.push(new Date(d));
}
Guilherme Simão Couto
  • 1,016
  • 2
  • 12
  • 24
0

Let us assume you got the start date and end date from the UI and stored it in the scope variable in the controller.

Then declare an array which will get reset on every function call so that on the next call for the function the new data can be stored.

var dayLabel = [];

Remember to use new Date(your starting variable) because if you dont use the new date and directly assign it to variable the setDate function will change the origional variable value in each iteration`

for (var d = new Date($scope.startDate); d <= $scope.endDate; d.setDate(d.getDate() + 1)) {
                dayLabel.push(new Date(d));
            }
Utkarsh Joshi
  • 141
  • 1
  • 3
-2

Based on Jayarjo's answer:

var loopDate = new Date();
loopDate.setTime(datFrom.valueOf());

while (loopDate.valueOf() < datTo.valueOf() + 86400000) {

    alert(loopDay);

    loopDate.setTime(loopDate.valueOf() + 86400000);
}
Tom Gullen
  • 61,249
  • 84
  • 283
  • 456
  • One comment for this is that a less than comparison is prefered over !=, as when loop over multiple months for some reason the != comparison never fires. – Tom Gullen Dec 03 '10 at 12:02
  • 1
    Besides DST, another edge condition is "Leap Second". A one second difference *does* matter - Dates converted to milliseconds correspond to first second of a given day. One second error and you land on previous day. – Wojtek Kruszewski May 27 '13 at 08:56