anon
anon

Reputation:

MomentJS possible bug with the add() function

I'd like to add several months in an array but I cannot get the add() function of MomentJS to work properly. Here's how it goes :

    function getMonths(begin, end){
        var cursor = moment(begin);
        var momentEnd = moment(end);
        var arrayMonths = [];
        while(cursor.month() != momentEnd.month() || cursor.year() != momentEnd.year()){        
            cursor.add(1, 'month'); // Actually adds one month to the cursor
            console.log(cursor.toDate()); // Because this display the cursor with an added month
            arrayMonths.push(cursor.toDate()); // However the cursor being pushed doesn't have this added month
            console.log(arrayMonths); // verified here
        }       
        return arrayMonths;
    }

The console log shows that the cursor has actually been incremented (as add() is a mutator) however its proper value isn't added to the array.

I cannot figure out if this is an issue in my code or if it is inherent to MomentJS. Does anybody have any clue ?

Thank you !

Upvotes: 0

Views: 186

Answers (2)

James Thorpe
James Thorpe

Reputation: 32212

The documentation for toDate says:

To get the native Date object that Moment.js wraps, use moment#toDate.

This will return the Date that the moment uses, so any changes to that Date will cause the moment to change. If you want a Date that is a copy, use moment#clone before you use moment#toDate.

IE you're getting the same underlying Date object every time you call toDate - ie each call to add is also modifying it, and every member of the array is actually the same object.

If you do as the documentation says, and use clone, your code works:

arrayMonths.push(cursor.clone().toDate());

Here's a demo:

function getMonths(begin, end){
  var cursor = moment(begin);
  var momentEnd = moment(end);
  var arrayMonths = [];
  while(cursor.month() != momentEnd.month() || cursor.year() != momentEnd.year()){        
    cursor.add(1, 'month'); // Actually adds one month to the cursor
    console.log(cursor.toDate()); // Because this display the cursor with an added month
    
    //clone the object before pushing, to ensure it's not further modified
    arrayMonths.push(cursor.clone().toDate()); 
    
    console.log(arrayMonths); // verified here
  }       
  return arrayMonths;
}
    
    
getMonths(moment('2016/01/01', 'YYYY/MM/DD'), moment('2017/01/01', 'YYYY/MM/DD'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.13.0/moment.js"></script>

Upvotes: 3

phuzi
phuzi

Reputation: 13059

Not entirely sure what's happening here as your code looks OK.

I would however try using and temporary variable to double check what's happening.

function getMonths(begin, end){
    var cursor = moment(begin);
    var momentEnd = moment(end);
    var arrayMonths = [];
    while(cursor.month() != momentEnd.month() || cursor.year() != momentEnd.year()){        
        cursor.add(1, 'month');
        var cursorDate = cursor.toDate();
        console.log(cursorDate); // temporary variable - no chance it gets mutated etc...
        arrayMonths.push(cursorDate); 
        console.log(arrayMonths);
    }       
    return arrayMonths;
}

Upvotes: -1

Related Questions