Steve
Steve

Reputation: 41

Function returns incorrect month depending on order of statements

Does anyone have any thoughts on why this might have happened? Today, I found that a date conversion function I wrote started returning the wrong month. For instance, when attempting to convert "2017-06-02" to "Fri Jun 02 2017 00:00:00 GMT-0600 (Mountain Daylight Time)", it actually returned July instead of June. When I re-arranged the order of some of the statements in the function, the correct date was finally returned. This code has been in place for many months, so this spontaneous...maybe due to the current month changing, as today is 5/31/17? This might only be broken when ran on todays date, or end-of-month? (I'm sure there's a better way to convert dates, but here's the code in question anyway):

<!doctype html>

<body onload="testDate()">

    <div id="resultbad"></div>
    <div id="resultgood"></div>

    <script>

        function testDate() {

            document.getElementById("resultbad").innerHTML = "Bad Result: Converting 2017-06-02 returns: " + badDate("2017-06-02");
            //returns: Bad Result: Converting 2017-06-02 returns: Sun Jul 02 2017 00:00:00 GMT-0600 (Mountain Daylight Time)

            document.getElementById("resultgood").innerHTML = "Good Result: Converting 2017-06-02 returns: " + goodDate("2017-06-02");
            //returns: Good Result: Converting 2017-06-02 returns: Fri Jun 02 2017 00:00:00 GMT-0600 (Mountain Daylight Time)

        }


        function badDate(d) {

            var td = d.split('-'); 

            var nd = new Date(); 

            //originally ordered:  Year, Month then Day
            nd.setFullYear(td[0]);
            nd.setMonth(td[1] - 1); 
            nd.setDate(td[2]); 

            //set time
            nd.setHours(0); 
            nd.setMinutes(0,0,0); 
            return nd; 

        }

        function goodDate(d) {

            var td = d.split('-'); 

            var nd = new Date(); 

            //new order:  Day, Month then Year
            nd.setDate(td[2]); 
            nd.setMonth(td[1] - 1); 
            nd.setFullYear(td[0]);

            //set time
            nd.setHours(0); 
            nd.setMinutes(0,0,0); 
            return nd; 

        }

    </script>


</body>

Upvotes: 0

Views: 38

Answers (2)

Prisoner
Prisoner

Reputation: 50701

You figured out the problem fairly well - it has to do with today being the 31st of the month.

The issue is that new Date() creates a date object with the fields filled in. You're then changing those fields one by one.

So right now we can think of it as having a pseudo-structure like this, remembering that month is 0-based:

{
  year: 2017
  month: 4
  date: 31
}

when you call setMonth(), you're just changing the month field, so you'd think for June it would set it to

{
  year: 2017
  month: 5
  date: 31
}

but it knows there aren't 31 days in June. The 31st "day" of June would be the 1st of July. So it helps you out and adjusts it to

{
  year: 2017
  month: 6
  date: 1
}

You're then setting the date to the 2nd with setDate():

{
  year: 2017
  month: 6
  date: 2
}

In the function that works, you're setting the date before the month, so you're not having it recompute what the day is in case you've specified a date that is larger than the number of days in the month.

Upvotes: 1

Jeremy
Jeremy

Reputation: 521

This code overrides the date elements based on today's date. So, if you are running the code on the 31st day of the month, the "bad" version of this code will overwrite the month first, and if that month only has 30 days, it will roll over to the next month.

Basically, after setMonth but before setDate, you are trying to create the date June 31, 2017, which JS will convert for you into July 1, 2017.

Instead, do this as one call:

new Date(td[0], td[1]-1, td[2], 0, 0, 0, 0)

Upvotes: 3

Related Questions