I would like to iterate through a range of calender dates, each iteration is +1 day. I would use something built around JodaTime in Java - is there something similar in NodeJS?
9 Answers
You can use moment.js in a node.js application.
npm install moment
Then you can very easily do this:
var moment = require('moment');
var a = moment('2013-01-01');
var b = moment('2013-06-01');
// If you want an exclusive end date (half-open interval)
for (var m = moment(a); m.isBefore(b); m.add(1, 'days')) {
  console.log(m.format('YYYY-MM-DD'));
}
// If you want an inclusive end date (fully-closed interval)
for (var m = moment(a); m.diff(b, 'days') <= 0; m.add(1, 'days')) {
  console.log(m.format('YYYY-MM-DD'));
}
Hmmm... this looks a lot like the code you already wrote in your own answer. Moment.js is a more popular library has tons of features, but I wonder which one performs better? Perhaps you can test and let us know. :)
But neither of these do as much as JodaTime. For that, you need a library that implements the TZDB in JavaScript. I list some of those here.
Also, watch out for problems with JavaScript dates in general. This affects NodeJS as well.
 
    
    - 1
- 1
 
    
    - 230,703
- 74
- 448
- 575
- 
                    2I second moment over date-utils – film42 Jun 19 '13 at 05:56
- 
                    in moment 2.10 m.add(1,'days') as increment part of for loop. – avances123 Sep 14 '15 at 16:02
- 
                    1Great answer! Keep in mind than in new `moment` version it is recommended to use `m.add(1, 'days')` (replace arguments) `Deprecation warning: moment().add(period, number) is deprecated. Please use moment().add(number, period).` – May 12 '16 at 10:33
- 
                    @MateuszRzepa - Updated. Thanks. – Matt Johnson-Pint May 12 '16 at 15:48
- 
                    `var m = moment(a);` might be better here. Cloning 'a' will leave the original date object intact. – Eddie Jun 14 '16 at 09:50
- 
                    1I encountered this problem wherein the last day of the range isn't included I solved it using this `m.diff(b, 'days') <= 0` instead of `m.isBefore(b)` – JohnnyQ Aug 08 '16 at 14:42
- 
                    I hit a problem here while trying the option with m.diff : When your end date has a time attached (in my case it was 3 p.m.) your loop will end with 1 more day, as the last m.diff is not a full day ... So careful while converting your date to moment! – Mr. Muh Dec 18 '16 at 14:35
- 
                    3If you want to include the last day, you can use `m.isSameOrBefore(b)` – mpen Aug 15 '17 at 01:45
- 
                    m.isSameOrBefore also exists – Daniel Khoroshko May 05 '18 at 10:45
I would propose a change to the earlier response by Matt. His code will cause a mutation on the a object. try this...
var moment = require('moment');
var a = moment('2013-01-01');
var b = moment('2013-06-01');
for (var m = moment(a); m.isBefore(b); m.add(1, 'days')) {
    console.log(m.format('YYYY-MM-DD'));
}
- 
                    `var a = moment('2013-01-01');` so `a` is already a `moment`, no need for `var m = moment(a)`. Should be: `for (var m = a; m.isBefore(b); m.add(1, 'days'))`. Also, I think I would prefer `while` loop over the suggested `for` loop. – oyalhi Jul 21 '18 at 20:21
- 
                    2@oyalhi `var m = a` would still have the effect of mutating `a` because they both refer to the same moment object. By doing `var m = moment(a)` it generates a new moment object and assigns that to `m`, which is mutated and `a` remains unchanged. – Guy Oct 23 '18 at 14:30
- 
                    I don't know what I was thinking. Thank you for the clarification @Guy. – oyalhi Oct 23 '18 at 15:05
Here's one solution without external libraries:
  var start = new Date('October 1, 2020 03:00:00Z');
  var now = new Date();
  for (var d = start; d < now; d.setDate(d.getDate() + 1)) {
    console.log(d);
  }
Result:
2020-10-01T03:00:00.000Z 2020-10-02T03:00:00.000Z 2020-10-03T03:00:00.000Z 2020-10-04T03:00:00.000Z 2020-10-05T03:00:00.000Z 2020-10-06T03:00:00.000Z
The Z at the end of the first date is for UTC. If you want your time zone, just remove the Z.
 
    
    - 5,025
- 4
- 29
- 64
Use the https://github.com/JerrySievert/node-date-utils framework, then you can iterate easily like this:
require('date-utils');
var d = new Date('2013-01-01');
var e = new Date('2013-06-01');
for(var i = d; i.isBefore(e); i.addDays(1)) {
  console.log(i.toFormat("YYYY-MM-DD"));  
}
 
    
    - 2,067
- 1
- 22
- 40
Another way using momentjs with lodash range:
let a = moment('2021-01-01');
let b = moment('2021-01-10');
_.range(b.diff(a, "d")).forEach((d) =>
  console.log(moment(a).add(d, "d").format("YYYY/MM/DD"))
);
If you don't want to use lodash, you can get a range like shown here
[...Array(b.diff(a, "d")).keys()].forEach((d) =>
  console.log(moment(a).add(d, "d").format("YYYY/MM/DD"))
);
 
    
    - 320
- 1
- 2
- 11
Alternative way using moment and while loop.
If you want an exclusive end date
let startDate = moment()
let endDate = moment().add(5, 'days')
while (endDate.isAfter(startDate)) {
    console.log(startDate.format('YYYY-MM-DD'))
    //increment by one day
   startDate = startDate.add(1, 'day')
}
If you want an inclusive end date
let startDate = moment()
let endDate = moment().add(5, 'days')
while (endDate.isSameOrAfter(startDate)) {
    console.log(startDate.format('YYYY-MM-DD'))
    //increment by one day
    startDate = startDate.add(1, 'day')
}
 
    
    - 1
- 1
A functional approach using Ramda and date-fns:
R = require('ramda')
D = require('date-fns')
start = new Date('2013-01-01')
end = new Date('2013-06-01')
numDays = D.differenceInDays(end, start)
R.times(n => D.addDays(start, n), numDays)
 
    
    - 17,000
- 12
- 60
- 86
you can do it without moment.
for (const date = new Date(2022, 10, 1); date < new Date(2022, 11, 1); date.setDate(date.getDate() + 1)) {
  console.log(date)
}
or even make it as iterate function
export function addDate(date: Date, value = 1) {
  const newDate = new Date(date)
  newDate.setDate(newDate.getDate() + value)
  return newDate
}
export function* iterateDate(startDate: Date, endDate: Date) {
  for (let date = startDate; date <= endDate; date = addDate(date))
    yield date
}
so that you can iterate like this
for (const date of iterateDate(new Date('2022-10-01'), new Date()))
  console.log(date)
 
    
    - 1,092
- 12
- 20
As much as there are many utilities for this, they might be cumbersome to integrate into a useful loop to check against data.
This should do the trick. It might be overkill, but you could very easily make this more argument based.
var moment = require('moment');
var _ = require('lodash');
function(collectionsWithDateValues){
  var slots = [];
  var hours = {
    start: 7,   // 7am
    end: 21,    // 9pm
    window: 2   // How long each item should be slotted for.
  };
  var rightNow  = moment().add(0, 'days').hours(hours.start).minute(0).second(0);
  var cutoff    = moment(rightNow).add(14,'days'); // Check the next 2 weeks.
  for( rightNow ; rightNow.isBefore(cutoff) ; rightNow.add(hours.window, 'hours') ){
    // Check if we're going beyond the daily cutoff, go to the next day
    if(rightNow.isAfter(moment(rightNow).hour(hours.end))){
      rightNow.add(1, 'days').hour(hours.start);
    }
    var foundClash = false;
    _.forEach(collectionsWithDateValues,  function(item){
      // Check if the item is within now and the slotted time 
      foundClash = moment(item.date).isBetween(rightNow, moment(rightNow).add(hours.window, 'hours').subtract(1, 'minutes').seconds(59));
    });
    if(!foundClash){
      slots.push(rightNow.toString());
    }
  }
  return slots;
}
 
     
    