JavaScript: неожиданный результат с количеством дней, оставшихся в месяце - PullRequest
0 голосов
/ 30 августа 2018

Я создаю простой скрипт, который показывает количество дней до конца месяца, чтобы продемонстрировать понимание того, как даты работают в Javascript. И это тоже хорошо, потому что у меня его явно нет.

Я хочу получить текущую дату и сравнить ее с последним днем ​​месяца как date(this year, this month +1, day 0) - 1 day, чтобы узнать, сколько осталось дней. Я мог бы построить массив, сообщающий, сколько дней в каждом месяце, но я должен иметь возможность использовать встроенное понимание дат для решения этой проблемы.

Для ожидаемого выхода, последний день этого месяца (31 августа) - сегодня (30 августа) = 1. Но я получаю 0.

Это то, что я имею до сих пор:

<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>

На данный момент это 11 в AEST (GMT + 1000), где я нахожусь в случае, если это поможет. Смысл в том, чтобы сделать что-то, что будет работать где угодно и когда угодно.


Мой первый подозреваемый - это часовые пояса - я подумал, что это могло бы сработать, если бы я использовал все UTC или не использовал UTC. Похоже, это не так. Я пытался запросить значения UTC в разных местах, но, как ни странно, только кажется, что может увеличить погрешность, поэтому он возвращает -1.

Ответы [ 3 ]

0 голосов
/ 30 августа 2018

Вы должны помнить, что в браузере даты всегда находятся в текущем системном часовом поясе.

Если вы можете использовать библиотеку моменты , которая может решить все распространенные проблемы, связанные с датой, предоставляя вам почти все функции, которые вам могут понадобиться

Вот пример кода с датой:

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);

теперь, поскольку обе даты созданы в одном и том же браузере, они будут иметь одинаковый часовой пояс и не создаст никаких проблем. Но если одна дата, скажем, возвращена с сервера и представлена, скажем, в GMT / UTC, то вам нужно также конвертировать другую дату в тот же часовой пояс. Опять же, в этом вам поможет моментов .js.

0 голосов
/ 30 августа 2018

Для тех, кто интересуется, почему нулевое значение дня приводит к такому поведению, JavaScript ... возвращает последнюю доступную дату календаря предоставляет полезное объяснение.

Следующий ванильный подход к вычислению дней, оставшихся в месяце, является лишь небольшим отклонением от того, что вы делаете, с кратким комментарием, объясняющим, как воспользоваться индексом месяца и нулевым днем, чтобы получить последний день текущего месяца.

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

// current datetime
let 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
let last = new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();

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

console.log(diff);

Ниже приведен фрагмент, в котором вы можете поэкспериментировать с результатами для разных дат.

const year = document.querySelector('#year');
const month = document.querySelector('#month');
const day = document.querySelector('#day');
const button = document.querySelector('button');
const result = document.querySelector('#result');

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

button.addEventListener('click', () => {
  remainDays(year.value, month.value, day.value);
});

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>
0 голосов
/ 30 августа 2018

Мне кажется, я только что наткнулся на ответ - при указании даты месяцы считаются от 0 до 11, а дни по-прежнему считаются от 1 до 31. Поэтому, указав

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

- это в основном сокращение для последнего дня текущего месяца. Следующая строка тогда избыточна:

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

Это даст неверный результат, так как в основном уменьшается во второй раз. Проблема не в UTC / nonUTC, а в неправильной спецификации дня. Не уверен, что эта стенография может вызвать другие проблемы в дальнейшем.

...