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

如何筛选当月提醒日期?JavaScript生成重复周期提醒日期错误排查

重复提醒日期计算功能修复

基础规则说明

从数据库获取的配置参数如下:

recurrence_Date = 2021-10-01,
recurevery=10, 
frequency=yearly 
reminder_setdaysbefore=30

提醒规则为:从项目起始日期开始,按指定周期重复,提前配置的天数发送提醒,如以上配置的提醒日期为2021-09-01、2031-09-01、2041-09-01,以此类推。
区间查询规则:

  • 若用户搜索区间为2031-01-01至2041-12-01,返回结果应为2031-09-01、2041-09-01
  • 若用户搜索区间为2031-01-01至2031-12-01,返回结果应为2031-09-01

现有问题说明

用到的JSON配置

{
   "projectremindshow":[
      {
         "project_ID":"1",
         "project_title":"Althurath",
         "period_type":"Monthly",
         "recurrence_date":"2021-01-01",
         "reminder_set_days":"30",
         "recur_every":"6",
         "start_date": "2020-12-02"
      },
      {
         "project_ID":"2",
         "project_title":"Help AG",
         "period_type":"Yearly",
         "recurrence_date":"2021-06-01",
         "reminder_set_days":"30",
         "recur_every":"1",
         "start_date": "2021-05-02"
      }
   ]
}

示例1错误

用户选择搜索区间2021-06-01 至 2021-06-31:

  • 当前返回结果:
[
    {
        "project": "Althurath",
        "reminderDate": "2021-05-02"
    },
    {
        "project": "Help AG",
        "reminderDate": "2021-05-02"
    }
]
  • 预期返回结果:
[
    {
        "project": "Althurath",
        "reminderDate": "2021-06-02"
    }
]

错误原因:Althurath项目起始日期为2020-12-02,每6个月重复一次,对应提醒日期应为2021-06-02,当前逻辑返回了早于搜索起始日期的结果。

示例2错误

用户选择搜索区间2021-01-01 至 2022-12-31,当前返回结果不符合预期,预期结果如下:

[
    {
        "project": "Althurath",
        "reminderDate": "2021-06-01"
    },
    {
        "project": "Althurath",
        "reminderDate": "2021-12-02"
    },
    {
        "project": "Althurath",
        "reminderDate": "2022-06-01"
    },
    {
        "project": "Help AG",
        "reminderDate": "2022-05-02"
    },
    {
        "project": "Althurath",
        "reminderDate": "2022-12-02"
    }
]

问题根因

  1. 逻辑顺序错误:现有代码先对起始日期减去提前提醒天数,再判断是否在搜索区间内,导致提前天数计算后得到的日期早于搜索起始日期也被返回。
  2. 首周期计算错误:没有先计算出第一个大于等于项目起始日期的重复周期节点,直接从基准日期开始计算,导致周期偏移。
  3. Yearly周期累加逻辑问题:直接修改原日期对象,没有使用拷贝的新对象,存在隐性错误。
  4. HTML结构错误:tbody的id属性多写了#,导致jQuery选择器无法匹配到对应DOM节点。

修复后的完整代码

JS代码

Date.prototype.addDays = function(days) {
  var date = new Date(this.valueOf());
  date.setDate(date.getDate() + days);
  return date;
}

Date.prototype.subtractDays = function(days) {
  var date = new Date(this.valueOf());
  date.setDate(date.getDate() - days);
  return date;
}

Date.prototype.addMonths = function(months) {
  var date = new Date(this.valueOf());
  var d = date.getDate();
  date.setMonth(date.getMonth() + months);
  if (date.getDate() != d) {
    date.setDate(0);
  }
  return date;
}

Date.prototype.addYears = function(years) {
  var date = new Date(this.valueOf());
  var d = date.getDate();
  date.setFullYear(date.getFullYear() + years);
  if (date.getDate() != d) {
    date.setDate(0);
  }
  return date;
}

var fromdate_recu_viewedit = "2021-06-01";
var todate_recu_viewedit = "2021-06-30"; // 修正6月没有31号的问题

const getPaymentPlan = ({
  dateFrom,
  dateTo,
  recurrenceDate,
  daysBefore,
  period,
  skip,
  title
}) => {
  skip = parseInt(skip);
  daysBefore = parseInt(daysBefore);
  let currentRecurDate = new Date(recurrenceDate.valueOf());
  let recurrenceList = [];

  // 先计算第一个晚于等于dateFrom的重复日期
  while (currentRecurDate.getTime() < dateFrom.getTime()) {
    switch (period) {
      case 'Monthly':
        currentRecurDate = currentRecurDate.addMonths(skip);
        break;
      case 'Yearly':
        currentRecurDate = currentRecurDate.addYears(skip);
        break;
      default:
        recurrenceList.push({
          "project": "wrong period type is given",
          "reminderDate": null
        })
        return recurrenceList;
    }
  }

  // 遍历所有符合区间的重复日期
  while (true) {
    // 计算提醒日期
    let reminderDate = currentRecurDate.subtractDays(daysBefore);
    // 提醒日期超过搜索结束日期就终止循环
    if (reminderDate.getTime() > dateTo.getTime()) {
      break;
    }
    // 提醒日期大于等于搜索起始日期才加入结果
    if (reminderDate.getTime() >= dateFrom.getTime()) {
      recurrenceList.push({
        "project": title,
        "reminderDate": reminderDate.toISOString().split('T')[0]
      });
    }
    // 计算下一个重复日期
    switch (period) {
      case 'Monthly':
        currentRecurDate = currentRecurDate.addMonths(skip);
        break;
      case 'Yearly':
        currentRecurDate = currentRecurDate.addYears(skip);
        break;
    }
  }

  return recurrenceList;
}


let new_data = {
  "projectremindshow": [{
    "project_ID": "1",
    "project_title": "Althurath",
    "period_type": "Monthly",
    "recurrence_date": "2021-01-01",
    "reminder_set_days": "30",
    "recur_every": "6",
    "start_date": "2020-12-02"
  }, {
    "project_ID": "2",
    "project_title": "Help AG",
    "period_type": "Yearly",
    "recurrence_date": "2021-06-01",
    "reminder_set_days": "30",
    "recur_every": "1",
    "start_date": "2021-05-02"
  }]
}

let inputList = [];

for (var i = 0; i < new_data.projectremindshow.length; i++) {
  var proj = new_data.projectremindshow[i];
  inputList.push({
    dateFrom: new Date(fromdate_recu_viewedit),
    dateTo: new Date(todate_recu_viewedit),
    daysBefore: proj.reminder_set_days,
    recurrenceDate: new Date(proj.start_date),
    period: proj.period_type,
    skip: proj.recur_every,
    title: proj.project_title
  });
}

let frequencyList = [];
for (let i = 0; i < inputList.length; i++) {
  let plan = getPaymentPlan(inputList[i]);
  Array.prototype.push.apply(frequencyList, plan);
}
frequencyList.sort(compare);

$.each(frequencyList, function(index, jsonObject) {
  var tableRow = '<tr>';
  $.each(Object.keys(jsonObject), function(i, key) {
    tableRow += '<td>' + jsonObject[key] + '</td>';
  });
  tableRow += "</tr>";
  $("#tablereminder").append(tableRow);
})

function compare(a, b) {
  if (a.reminderDate < b.reminderDate) {
    return -1;
  }
  if (a.reminderDate > b.reminderDate) {
    return 1;
  }
  return 0;
}

HTML代码

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<table>
  <tbody id="tablereminder"></tbody>
</table>

额外修正说明

  • 新增addYears日期原型方法,统一日期操作逻辑,避免直接修改原日期对象
  • 修正了6月没有31日的错误日期输入,避免日期对象自动跳转月份导致的计算偏差
  • 新增参数类型转换,确保数字类型参数不会因字符串类型导致计算错误

内容的提问来源于stack exchange,提问作者Remesh sree

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 05:54:01