基于三个日期条件统计符合要求的还款月份差值
问题描述
已知贷款放款日期为05-12-2023,每月EMI收款日为当月第一个周六,我需要统计从放款日到当前日期之间包含多少个该收款日,以此确定应还款的月份数。以下是我正在使用的JavaScript代码:
$(document).ready(function () { initializeDateInputs(); // Function to calculate attendance percentage function calculateAttendancePercentage() { var checkedCount = $('input[name="pstatus[]"]:checked').length; // Count of checked checkboxes var totalRowCount = $('#lcount').val(); // Total row count // Calculate the percentage of checked checkboxes var checkedPercentage = (checkedCount / totalRowCount) * 100; return checkedPercentage; } // Function to update submit button state based on attendance percentage function updateSubmitButton() { var attendancePercentage = calculateAttendancePercentage(); if (attendancePercentage >= 50) { $('#submit').prop('disabled', false); } else { $('#submit').prop('disabled', true); } } // Initial calculation and button state update updateSubmitButton(); // Event listener for attendance checkboxes change $('input[name="pstatus[]"]').change(function () { updateSubmitButton(); var checkedPercentage = calculateAttendancePercentage(); // Show toast messages based on attendance percentage if (checkedPercentage >= 50) { Swal.fire({ toast: true, position: 'top-right', showConfirmButton: false, timer: 5000, icon: 'success', title: 'Scheduled Meeting', text: 'You have reached 50% attendance requirement. You can now submit the form.', customClass: { background: 'bg-green', // Apply bg-green class for success }, }); } else { Swal.fire({ toast: true, position: 'top-right', showConfirmButton: false, timer: 5000, icon: 'error', title: 'Scheduled Meeting', text: 'Please ensure at least 50% attendance to submit the form!', customClass: { background: 'bg-danger', // Apply bg-green class for success }, }); } }); // Calculate arrear demand when EMI date changes calculateArrearDemand(); async function calculateArrearDemand() { const disdateValue = $("#disdate").val(); const lrddateValue = $("#lrd").val(); if (!disdateValue) { console.error("Disbursement date is not defined"); return; } if (!lrddateValue) { console.error("Loan repayment day is not defined"); return; } const disbursementDate = parseDate(disdateValue); const currentDate = new Date(); if (!disbursementDate || !currentDate) { console.error("Invalid disbursement date or current date"); return; } const monthDifference = calculateMonthsDifference(disbursementDate, currentDate, lrddateValue); console.log("Month difference:", monthDifference); } // Calculate the difference in months based on disbursement date, current date, and loan repayment day function calculateMonthsDifference(disdate, currentDate, lrddate) { let monthDifference = 0; let currentMonth = disdate.getMonth(); let currentYear = disdate.getFullYear(); while (currentYear < currentDate.getFullYear() || (currentYear === currentDate.getFullYear() && currentMonth <= currentDate.getMonth())) { if (containsNthDayOfMonth(currentYear, currentMonth, lrddate)) { monthDifference++; } currentMonth++; if (currentMonth > 11) { currentMonth = 0; // January currentYear++; } } return monthDifference; } // Check if the specified month contains the nth occurrence of the specified day function containsNthDayOfMonth(year, month, lrddate) { const [occurrenceStr, dayOfWeekStr] = lrddate.split(' '); const occurrence = parseInt(occurrenceStr[0], 10); // e.g., "1st" -> 1 const dayOfWeek = getDayIndex(dayOfWeekStr); // e.g., "Saturday" -> 6 if (isNaN(occurrence) || dayOfWeek === -1) { console.error("Invalid occurrence or day of week"); return false; } let count = 0; for (let day = 1; day <= 31; day++) { const date = new Date(year, month, day); if (date.getMonth() !== month) break; // Stop if we've moved to the next month if (date.getDay() === dayOfWeek) { count++; if (count === occurrence) return true; } } return false; } function parseDate(dateStr) { if (!dateStr) { console.error("Invalid date string:", dateStr); return null; } const parts = dateStr.split('-'); if (parts.length !== 3) { console.error("Invalid date format:", dateStr); return null; } return new Date(parts[2], parts[1] - 1, parts[0]); } function getDayIndex(dayName) { const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; return days.indexOf(dayName); } // Function to initialize date inputs function initializeDateInputs() { const disdateInput = document.getElementById('disdate'); const lrddateInput = document.getElementById('lrd'); if (!disdateInput || !lrddateInput) { console.error("One or more date input elements are missing"); return; } const currentDate = new Date(); console.log("Current date:", formatDate(currentDate)); } function formatDate(date) { if (!date) return null; const year = date.getFullYear(); const month = (date.getMonth() + 1).toString().padStart(2, '0'); const day = date.getDate().toString().padStart(2, '0'); return `${day}-${month}-${year}`; } // Form submission handling $('#formScheduled').on('submit', function (e) { e.preventDefault(); var form = $(this); var gid = $("#gid").val(); if (gid == "") { $("#gid").closest('.form-control form-control-sm').addClass('has-error'); $("#gid").after('<p class="text-danger">Please enter group name!<br></p>'); } else { $("#gid").closest('.form-control form-control-sm').removeClass('has-error').addClass('has-success'); } if (gid) { $.ajax({ url: "AppController/addScheduledMeeting", method: "POST", data: new FormData(this), contentType: false, cache: false, processData: false, dataType: 'json', success: function (response) { $(".form-control form-control-sm").removeClass("has-error has-success"); if (response.success == true) { Swal.fire({ icon: "success", title: "Good Job!", text: "Meeting scheduled Successfully", showConfirmButton: false, timer: 5000, }); window.location.reload(); } else { Swal.fire({ icon: "error", title: "Oops...", text: "An error occurred. Please try again later.", showConfirmButton: false, timer: 5000, }); } }, error: function () { Swal.fire({ icon: "error", title: "Oops...", text: "An error occurred. Please try again later.", showConfirmButton: false, timer: 5000, }); } }); } return false; }); });
代码问题与修正
原代码的calculateMonthsDifference函数仅判断当月是否存在目标收款日,但未覆盖两个核心场景:
- 放款当月的收款日是否晚于或等于放款日期(比如放款日为12月5日,当月第一个周六是12月2日,早于放款日,不应计入)
- 当前月份的收款日是否早于或等于当前日期(比如当前日期是12月3日,当月第一个周六是2日,已过,需计入;若当前日期是12月1日,还未到,不计入)
我们需要调整函数逻辑,先获取当月收款日的具体日期,再做针对性判断:
// 修正:返回当月目标收款日的具体日期,不存在则返回null function getNthDayOfMonth(year, month, lrddate) { const [occurrenceStr, dayOfWeekStr] = lrddate.split(' '); const occurrence = parseInt(occurrenceStr[0], 10); const dayOfWeek = getDayIndex(dayOfWeekStr); if (isNaN(occurrence) || dayOfWeek === -1) { console.error("Invalid occurrence or day of week"); return null; } let count = 0; for (let day = 1; day <= 31; day++) { const date = new Date(year, month, day); if (date.getMonth() !== month) break; if (date.getDay() === dayOfWeek) { count++; if (count === occurrence) return date; } } return null; } // 修正:加入日期判断逻辑 function calculateMonthsDifference(disdate, currentDate, lrddate) { let monthDifference = 0; let currentMonth = disdate.getMonth(); let currentYear = disdate.getFullYear(); while (currentYear < currentDate.getFullYear() || (currentYear === currentDate.getFullYear() && currentMonth <= currentDate.getMonth())) { const emiDate = getNthDayOfMonth(currentYear, currentMonth, lrddate); if (emiDate) { const isDisbursementMonth = currentYear === disdate.getFullYear() && currentMonth === disdate.getMonth(); const isCurrentMonth = currentYear === currentDate.getFullYear() && currentMonth === currentDate.getMonth(); // 非放款/当前月份直接计入;放款月份需收款日>=放款日;当前月份需收款日<=当前日期 if ((!isDisbursementMonth && !isCurrentMonth) || (isDisbursementMonth && emiDate >= disdate) || (isCurrentMonth && emiDate <= currentDate)) { monthDifference++; } } currentMonth++; if (currentMonth > 11) { currentMonth = 0; currentYear++; } } return monthDifference; }
测试验证
以放款日05-12-2023(2023年12月5日)、收款日为每月第一个周六为例:
- 2023年12月第一个周六是12月2日,早于放款日,不计入
- 2024年1月第一个周六是1月6日,计入
- 2024年2月第一个周六是2月3日,计入
- 若当前日期为2024年3月10日,3月第一个周六是3月2日,早于当前日期,计入
- 最终统计结果为3
内容的提问来源于stack exchange,提问作者deepakparam
相关产品推荐
相关产品推荐

