UUake Up UUake Up - 1 year ago 73
Javascript Question

Oddities with JS Date() Object

Ok so I'm writing a simple script that you can feed any year into and it will spit out the number of days in each month of that year. My function looks something like this:

function( year ){
var months = [];
var date = new Date();
date.setFullYear( year );


for( i = 1; i < 13; i++ ){
date.setMonth( i );
date.setDate( 0 );
months[i] = date.getDate();
console.log([date, i, date.getMonth()]);
}

console.log(months);
return months;
}


Should work a treat as far as I'm aware but the strangest thing occurs around August. Here's the console log:

VM691:10 [Sun Jan 31 2016 12:31:41 GMT+0000 (GMT), 1, 0]
VM691:10 [Mon Feb 29 2016 12:31:41 GMT+0000 (GMT), 2, 1]
VM691:10 [Thu Mar 31 2016 12:31:41 GMT+0100 (BST), 3, 2]
VM691:10 [Sat Apr 30 2016 12:31:41 GMT+0100 (BST), 4, 3]
VM691:10 [Tue May 31 2016 12:31:41 GMT+0100 (BST), 5, 4]
VM691:10 [Thu Jun 30 2016 12:31:41 GMT+0100 (BST), 6, 5]
VM691:10 [Sun Jul 31 2016 12:31:41 GMT+0100 (BST), 7, 6]
VM691:10 [Fri Sep 30 2016 12:31:41 GMT+0100 (BST), 8, 8]
VM691:10 [Fri Sep 30 2016 12:31:41 GMT+0100 (BST), 9, 8]
VM691:10 [Mon Oct 31 2016 12:31:41 GMT+0000 (GMT), 10, 9]
VM691:10 [Wed Nov 30 2016 12:31:41 GMT+0000 (GMT), 11, 10]
VM691:10 [Sat Dec 31 2016 12:31:41 GMT+0000 (GMT), 12, 11]
VM691:13 [1: 31, 2: 29, 3: 31, 4: 30, 5: 31, 6: 30, 7: 31, 8: 30, 9: 30, 10: 31, 11: 30, 12: 31]


As you can see September is read twice even though the i count clearly states August (note setMonth(i) takes the months in the classic order i.e. 1 = January, but getMonth() returns them in a programmatic order 0 = January). So I did a little digging and turns out that when the setMonth method is explicitly set to 8 (August) the console returns a list that fluctuates between August and September:

VM757:10 [Wed Aug 31 2016 12:36:12 GMT+0100 (BST), 1, 7]
VM757:10 [Fri Sep 30 2016 12:36:12 GMT+0100 (BST), 2, 8]
VM757:10 [Wed Aug 31 2016 12:36:12 GMT+0100 (BST), 3, 7]
VM757:10 [Fri Sep 30 2016 12:36:12 GMT+0100 (BST), 4, 8]
VM757:10 [Wed Aug 31 2016 12:36:12 GMT+0100 (BST), 5, 7]
VM757:10 [Fri Sep 30 2016 12:36:12 GMT+0100 (BST), 6, 8]
VM757:10 [Wed Aug 31 2016 12:36:12 GMT+0100 (BST), 7, 7]
VM757:10 [Fri Sep 30 2016 12:36:12 GMT+0100 (BST), 8, 8]
VM757:10 [Wed Aug 31 2016 12:36:12 GMT+0100 (BST), 9, 7]
VM757:10 [Fri Sep 30 2016 12:36:12 GMT+0100 (BST), 10, 8]
VM757:10 [Wed Aug 31 2016 12:36:12 GMT+0100 (BST), 11, 7]
VM757:10 [Fri Sep 30 2016 12:36:12 GMT+0100 (BST), 12, 8]
VM757:13 [1: 31, 2: 30, 3: 31, 4: 30, 5: 31, 6: 30, 7: 31, 8: 30, 9: 31, 10: 30, 11: 31, 12: 30]


When set 9 it returns only September and at 7 only July, so what gives?

Any help would be greatly appreciated. Cheers

Answer Source

Step through your code and see what happens:

  • Initial setup, date = 13/Sep/2016
  • Enter loop
  • Set month to 1, date = 13/Feb/2016
  • Set day to 0, date = 0/Feb/2016 = 31/Jan/2016
  • Log details
     

  • Second iteration of loop:

  • Set month to 2, date = 31/Mar/2016
  • Set day to 0, date = 0/Mar/2016 = 29/Feb/2016
  • Log details

This works fine, up until August.

  • Set month to 8, date = 30/Aug/2016
  • Set day to 0, date = 0/Aug/2016 = 31/Jul/2016
  • Log details
     

  • Set month to 9, date = 31/Sep/2016 = 1/Oct/2016 !!!

  • Set date to 0, date = 0/Oct/2016 = 30/Sep/2016
  • Log details - "august" is logged as having 30 days

To solve this problem, call setDate(1) at the start of your loop, to ensure you won't have any overflow problems when setting the month.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download