You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于三个日期条件统计符合要求的还款月份差值

问题描述

已知贷款放款日期为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('&lt;p class="text-danger"&gt;Please enter group name!&lt;br&gt;&lt;/p&gt;');
    } 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函数仅判断当月是否存在目标收款日,但未覆盖两个核心场景:

  1. 放款当月的收款日是否晚于或等于放款日期(比如放款日为12月5日,当月第一个周六是12月2日,早于放款日,不应计入)
  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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 00:47:34