Isaac Reefman
Isaac Reefman

Reputation: 597

JavaScript: unexpected result getting number of days remaining in the month

I'm building a simple script to show the number of days to the end of the month to demonstrate an understanding of how dates work in Javascript. Which is just as well, because I clearly don't have one.

I want to get the current date, and compare it to the last day of the month, as date(this year, this month +1, day 0) - 1 day to see how many days are left. I could build an array telling it how many days are in each month, but I should be able to use the inbuilt understanding of dates to resolve this.

For expected output, last day of this month (Aug 31) - today (Aug 30) = 1. But I'm getting 0.

This is what I have so far:

<p id="demo"></p>

<script>
var d = new Date();
var nxt = new Date(d.getFullYear(), d.getMonth() + 1, 0);
nxt.setDate(nxt.getDate() - 1);
document.getElementById("demo").innerHTML = nxt.getDay() - d.getDay();
</script>

At the moment it's 11 in AEST (GMT + 1000), which is where I'm at in case that's of any help. Point is to make something that would work anywhere, any time.


My first suspect is timezones - I thought that this might even out if I used all UTC or no UTC explicits. It doesn't seem to be doing so though. I've tried asking for UTC values in a range of different places, but oddly only seem to be able to increase the inaccuracy so it returns -1.

Upvotes: 2

Views: 239

Answers (3)

benvc
benvc

Reputation: 15120

For anyone wondering why the day zero value results in that behavior, JavaScript... return last available date of calendar provides a useful explanation.

The following vanilla js approach to calculating days remaining in the month is just a slight variation on what you are doing with brief comment explanation of how to take advantage of month index and day zero to get the last day of the current month.

const year = 2018;
const month = 7; // months indexed from 0 (Jan) to 11 (Dec)
const day = 30;

// current datetime
const date = new Date(year, month, day);

// add 1 to get next month, set day to 0 to roll it back to last day of current month
const last = new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();

// difference between last day of the month and input date
const diff = last - date.getDate();
console.log(diff);

Below is a snippet where you can experiment with the results for different dates.

const remainDays = (y, m, d) => {
  const result = document.querySelector('#result');
  const date = new Date(y, m, d);
  const last = new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
  const diff = last - date.getDate();
  result.textContent = diff;
};

const year = document.querySelector('#year');
const month = document.querySelector('#month');
const day = document.querySelector('#day');
const button = document.querySelector('button');
remainDays(year.value, month.value, day.value);
button.addEventListener('click', () => {
  remainDays(year.value, month.value, day.value);
});
div {
  padding: 5px;
  display: flex;
  flex-direction: column;
  max-width: 400px;
}
<div>
  <label for="year">Year</label>
  <input id="year" name="year" type="text" value="2018" />
</div>
<div>
  <label for="month">Month Index</label>
  <input id="month" name="month" type="text" value="7" />
  <span>Enter month index between 0 (Jan) and 11 (Dec)</span>
</div>
<div>
  <label for="day">Day</label>
  <input id="day" name="day" type="text" value="30" />
</div>
<div>
  <button>Get Month Days Remaining</button>
</div>
<div>
  <span>Result:</span>
  <span id="result"></span>
</div>

Upvotes: 1

Isaac Reefman
Isaac Reefman

Reputation: 597

I believe I just stumbled on the answer - when specifying a date months are counted from 0 to 11, but days are still counted from 1 to 31. Therefore, specifying

Date(d.getFullYear(), d.getMonth() + 1, 0);

is basically shorthand for the last day of the current month. The next line is then redundant:

nxt.setDate(nxt.getDate() - 1);

This will give an incorrect result, as it basically decrements a second time. The problem is not with UTC/nonUTC, but rather incorrect day specification. Not sure if this shorthand could cause other problems further down the line though.

Upvotes: 2

Anant Anand Gupta
Anant Anand Gupta

Reputation: 738

You have to remember that in browser the dates are always in the current system setting timezone.

If you can use the moments library, that can solve all the date related common problems by providing you almost all the functions you may need

Here is the datediff sample code:

var today = new Date(), y = today.getFullYear(), m = today.getMonth();
var lastDay = new Date(y, m + 1, 0);
var diff = lastDay.diff(today, 'days', true);

now since both the dates are created in the same browser they will have same timezone an will not create any issue. But if one date is say returned from server and is represented in say GMT/UTC then you need to convert the other date too in the same timezone. Again, the moments.js will be able to help there.

Upvotes: 0

Related Questions