Расчет даты Javascript возвращает неверные значения

У меня есть калькулятор даты javascript, который иногда работает, а иногда нет. Я прочитал Как получить количество дней между двумя датами в JavaScript?, но я не уверен, где реализовать какое-либо из предложений, поскольку мне кажется, что даты в этом посте предопределены внутри кода, а не через входные данные.

Например, если вы введете дату 1 октября 2019 года, вы получите результаты:

45 дней: четверг, 14 ноября 2019 г.

180 дней: воскресенье, 29 марта 2020 г.

Но если вы введете дату 1 декабря 2019 года, вы получите результаты:

45 дней: среда, 15 января 2020 г.

180 дней: пятница, 29 мая 2020 г.

Это не может быть правильным, потому что в декабре 31 день. 31 + 15 = 46? Какой-то просчет происходит в большинстве месяцев.

(function ($) {
    var weekdays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
    var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];

    var afterTime = function (time, days) {
        time = time + (24 * 60 * 60 * 1000) * days;
        return time;
    };

    var getDate = function () {
        var yy = $('input#year').val();
        var mm = $('select#month').val();
        var dd = $('input#day').val();
        var wd;

        if (yy.trim().length === 0 || mm.trim().length === 0 || dd.trim().length === 0) {
            return;
        }

        var startDate = new Date(yy, mm, dd);
        var resultDate;

        resultDate = new Date();
        resultDate.setTime(afterTime(startDate.getTime(), 45));
        yy = resultDate.getFullYear();
        mm = resultDate.getMonth();
        dd = resultDate.getDate();
        wd = resultDate.getDay();
        $('#dateAfter45').html('<span>Your 45 Days from now ends on:</span> ' + weekdays[wd] + ', ' + months[mm] + ' ' + dd + ', ' + yy);

        resultDate = new Date();
        resultDate.setTime(afterTime(startDate.getTime(), 180));
        yy = resultDate.getFullYear();
        mm = resultDate.getMonth();
        dd = resultDate.getDate();
        wd = resultDate.getDay();
        $('#dateAfter180').html('<span>Your 180 Days from now ends on:</span> ' + weekdays[wd] + ', ' + months[mm] + ' ' + dd + ', ' + yy);
    };

    $(document).ready(function () {
        $('input#year').change(function () {
            getDate();
        });
        $('input#day').change(function () {
            getDate();
        });
        $('select#month').change(function () {
            getDate();
        });
    });

})(jQuery);
<script src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class = "dateselector">
            <div class = "start-date">
                <form class = "form">
                    <div class = "form-row align-items-center">
                        <div class = "col-auto">
                            <!--label for = "month">Month</label-->
                            <select name = "month" id = "month" class = "form-control">
                                <option value = "" disabled selected>- Select a Month -</option>
                                <option value = "0">January</option>
                                <option value = "1">February</option>
                                <option value = "2">March</option>
                                <option value = "3">April</option>
                                <option value = "4">May</option>
                                <option value = "5">June</option>
                                <option value = "6">July</option>
                                <option value = "7">August</option>
                                <option value = "8">September</option>
                                <option value = "9">October</option>
                                <option value = "10">November</option>
                                <option value = "11">December</option>
                            </select>
                        </div>
                        <div class = "col-auto">
                            <!--label for = "day">Day</label-->
                            <input type = "text" name = "day" id = "day" class = "form-control" placeholder = "Day" maxlength = "2">
                        </div>
                        <div class = "col-auto">
                            <!--label for = "day">Year</label-->
                            <input type = "text" name = "year" id = "year" class = "form-control" placeholder = "Year" maxlength = "4">
                        </div>
                        <div class = "col-auto">
                            <!--label for = "day">Year</label-->
                            <span class = "butn hvr-sweep-to-top">Calculate</span>
                        </div>
                    </div>
                </form>
            </div>
            <div class = "result-date">
                <h4 id = "dateAfter45"></h4>
                <h4 id = "dateAfter180"></h4>
            </div>
        </div>

Почему вы делаете свою собственную арифметику дат, а не просто resultdaDate.setDate(resultDate.getDate() + 45)?

Barmar 16.07.2019 02:53

Я не уверена. Взял бы я это и просто заменил: resultDate.setTime(afterTime(startDate.getTime(), 45));?

boloneysandwich 16.07.2019 03:45

Да, используйте это вместо resultDate.setTime(afterTime(startDate.getTime(), 45));

Barmar 16.07.2019 03:46

В результате вы все равно получите 15 января.

Barmar 16.07.2019 03:47

Я понимаю, что в месяце нет "0", но что можно сделать, чтобы это исправить?

boloneysandwich 16.07.2019 03:50

Я обновил ответ, чтобы объяснить, почему вы получаете 14 ноября вместо 15 ноября.

Barmar 16.07.2019 03:57

замена resultDate.setTime(afterTime(startDate.getTime(), 45)); на resultDate.setDate(resultDate.getDate() + 45); возвращает текущую дату без учета входных значений, см. здесь: codepen.io/chuckers82/pen/GbbLWr

boloneysandwich 16.07.2019 05:15

Я вошел 1 октября 2019 года, там было написано 15 ноября 2019 года.

Barmar 16.07.2019 08:16
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
8
50
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

45 — это 31 + 14. 31 день после 1 декабря — это 1 января, 14 дней после 1 января — это 15 января.

Результат правильный. Арифметика даты, которая пересекает границы месяца, смещена на 1, потому что в месяцах нет дня 0.

Причина, по которой вы получаете 14 ноября в первом случае, заключается в том, что переход на летнее время происходит где-то в октябре. Ваша функция afterTime() считает, что все дни длятся 24 часа, но когда заканчивается летнее время, мы добавляем к этому дню дополнительный час. Итак, вы переходите от Oct 1 00:00:00 к Nov 14 23:00:00 вместо Nov 15 00:00:00.

Используйте встроенную арифметику дат в классе Date, она автоматически подстраивается под это.

resultDate.setTime(afterTime(startDate.getTime(), 45));

Хорошо, так как я могу это исправить??

boloneysandwich 16.07.2019 03:43

Исправить что? В этом нет ничего плохого. Ваше ожидание неверно, результат правильный. Это дата через 45 дней после 1 декабря.

Barmar 16.07.2019 03:44

это пример, который я сделал для краткого расчета дней недели и месяца, надеюсь, это тоже поможет вам

Date.prototype.calculateDays = function(days) {
   var date = new Date(this.valueOf());
   //here you can enter the date you picked
   date.setDate(date.getDate() + days);
   return date;
}

var options = {
          weekday: 'long',
          year: 'numeric',
          month: 'long',
          day: 'numeric'
        };
        
let resultDate = new Date();
let firstDate = resultDate.calculateDays(45).toLocaleDateString('en-US', options);
console.info(firstDate);
        
let secondDate = resultDate.calculateDays(180).toLocaleDateString('en-US', options);
console.info(secondDate);

Другие вопросы по теме