Как посчитать количество дней между датами в JavaScript — и почему днём получается на один меньше
Ты делаешь счётчик «до отпуска осталось N дней». Отпуск 20 октября, сегодня 14-е. На пальцах — шесть дней. Код из первого ответа поисковика говорит: пять.
Ты обновляешь страницу утром, днём, вечером — всё время пять. Весь день счётчик на единицу меньше календаря. И только ровно в полночь на миг показывает шесть.
Всё дело в том, что Date в JavaScript хранит не день, а момент: дату плюс время до миллисекунды. Когда ты вычитаешь даты, ты считаешь не «дни в календаре», а «сколько раз по 24 часа поместилось». В 15:00 14 октября до полуночи 20-го помещается 5,375 суток. Math.floor честно отрезает дробь — и получается пять.
Давай посчитаем правильно. По шагам.
Что понадобится
Браузер с консолью (F12) или Node.js. Никаких библиотек — для основного решения хватит встроенного Date.
Пошагово
-
Реши, что ты считаешь. Есть два разных вопроса. «Сколько календарных дней до 20-го» — для отпусков, дедлайнов, стриков. «Сколько прошло полных суток» — для таймеров и подписок по часам. Почти всегда тебе нужен первый. Дальше — про него.
-
Отрежь время. Нам нужны только год, месяц и день. Берём их у даты и собираем новую дату на полночь:
const today = new Date() const y = today.getFullYear(), m = today.getMonth(), d = today.getDate() -
Собери полночь в UTC, а не в местном времени. Тут спрятана вторая ловушка. Во многих странах есть переход на летнее время. В день перехода сутки длятся 23 или 25 часов. Если вычитать местные полуночи, иногда получится 0,958 суток вместо одних.
Date.UTCпереходов не знает: там в сутках всегда ровно 86 400 000 миллисекунд.function daysBetween(a, b) { const utcA = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate()) const utcB = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate()) return Math.round((utcB - utcA) / 86_400_000) }Разница теперь всегда целая.
Math.roundздесь просто страховка. -
Правильно читай дату из
<input type="date">. Поле отдаёт строку вида"2026-10-20". Хочется написатьnew Date(value). Но строка без времени по стандарту читается как полночь по UTC. В Москве это 03:00, и всё хорошо. А в Нью-Йорке это вечер 19 октября — иgetDate()вернёт 19. Пользователь за океаном получит лишний день. Разбирай строку руками:function parseDateInput(value) { const [y, m, d] = value.split("-").map(Number) return new Date(y, m - 1, d) // месяцы в JS с нуля! }Да,
m - 1— не опечатка. Январь вDate— это 0, декабрь — 11. Забыл вычесть — и все даты уехали на месяц вперёд. Если в поле пусто,valueбудет пустой строкой, а результат —Invalid Date. Вычтешь из такой даты что угодно — получишь NaN. Проверь поле до расчёта. -
Собери счётчик.
const target = parseDateInput("2026-10-20") const left = daysBetween(new Date(), target) // 6 — в любой час и в любом часовом поясе -
Если браузеры позволяют — возьми Temporal. Это новый встроенный API для дат, и там «просто дата без времени» существует сама по себе:
Temporal.PlainDate.from("2026-10-14").until("2026-10-20").days // 6Ни часов, ни поясов, ни месяцев с нуля. Его поддерживают Chrome и Edge с версии 144 (январь 2026) и Firefox с версии 139. Safari — пока нет, поэтому для iPhone нужен полифил
temporal-polyfillили@js-temporal/polyfill.
Что получится
Счётчик, который показывает одно и то же число с утра до вечера и у пользователя в Москве, и в Берлине, и в Нью-Йорке. Он меняется ровно в полночь по местному времени — как и ждёт человек.
Проверь на трёх случаях, прежде чем считать задачу сделанной:
- даты в один день, но в разное время → должно быть 0;
- 31 декабря → 1 января → 1;
- если ты не в России — даты по обе стороны перехода на летнее время → без дробей.
А как прибавить к дате месяц?
Осторожно. setMonth(getMonth() + 1) от 31 января даст 3 марта: в феврале нет 31-го, и лишние дни перетекают дальше. Temporal и библиотеки вроде date-fns в таком случае прижимают дату к последнему дню месяца — 28 февраля. Обычно ты хочешь именно этого.
Почему у ИИ-кода тот же баг?
Потому что в интернете больше всего примеров Math.floor((b - a) / 86400000). Модель повторяет самый частый вариант. Попроси прямо: «считай календарные дни через Date.UTC, без учёта времени». Хорошо помогает, когда ты пишешь промпт с готовыми тестами из списка выше.
Нужна ли библиотека для дат?
Для разницы в днях — нет, хватит функции выше. Библиотека окупается, когда появляются повторяющиеся события, разные часовые пояса у пользователей и форматирование на десяти языках. До тех пор это лишний вес.
Короткие уроки-истории, симулятор агента и ежедневная практика — в нашем мобильном приложении. Бесплатно.




