【问题标题】:What is the best way to determine the number of business days between two dates in JavaScript?在 JavaScript 中确定两个日期之间的工作日数的最佳方法是什么?
【发布时间】:2020-06-22 01:54:04
【问题描述】:

我想创建一个计算截止日期的东西,知道开始日期和所需天数。例如,我在 7 月 6 日开始一些项目,我认为我需要 12 天才能完成它,所以我的算法的结果将是 7 月 21 日,因为我在周六和周日休息。

我的问题是我也在一些特殊的日子里休息,比如 7 月 14 日(我住在法国,7 月 14 日是休息日)。

这是我当前的脚本:


function generateEndDate(fromDate,total_days) {
    let startDate = new Date(fromDate);
    let endDate = new Date(fromDate);
    let tmpDate = new Date(fromDate); //a bit redundant I know
    endDate.setDate(endDate.getDate()+total_days);
    let daysOff = 0;
    let extraDaysOff = 0;
    for(let i = 0; i<=total_days; i++){
        tmpDate.setDate(tmpDate.getDate() + 1)
        if(tmpDate.getDay() === 6 || tmpDate.getDay() === 0 || joursFeriesAnnee.includes(tmpDate.toISOString().slice(0, 10))){
            daysOff++;
        }
    }
    endDate.setDate(startDate.getDate() + total_days + daysOff)
    if(endDate.getDay() != 6 || endDate.getDay() != 0 || joursFeriesAnnee.includes(endDate.toISOString().slice(0, 10))){
        if(endDate.getDay() === 6){
            extraDaysOff += 2;
        }else if(endDate.getDay() === 0 || joursFeriesAnnee.includes(endDate.toISOString().slice(0, 10))){
            extraDaysOff +=1;
        }
    }
    console.log(daysOff);
    console.log(extraDaysOff);
    console.log(endDate.toISOString().slice(0, 10));
    endDate.setDate(endDate.getDate() + daysOff + extraDaysOff)
    $(date_fin_input).val(endDate.toISOString().slice(0, 10))
    
}

joursFeriesAnnee 是一个数组,在法国今年每天休息, 如果截止日期是在周末或休息日,那么我会跳到下一个星期一/天(如果最后一天是星期五,但它也在 joursFeriesAnnee 或者星期一在 joursFeriesAnnee,我的算法会有问题。但是对于现在我没有遇到这种情况。

i/o 示例:

fromDate = 15/06/2020
total days = 23

my output = 19/08/2020
expected output = 17/07/2020 (4 weekends + 14th of July = 9 days off)

and my console.logs outputs:

6
0
2020-08-19

我该如何处理?

澄清

如果我需要 1 天,截止日期应与开始日期相同
如果开始日是星期五,那么星期五 + 1 是星期一
如果开始日是周四,周五是节假日,那么周四 + 1 是周一
如果在 250 天之类的某个时间段内,周末 + 假期的数量返回如下:startingDay +(周末 + 假期)= 周六、周日或圣日,那么我需要通过添加本周末或假期将我的截止日期调整为下一周或下一天在我的休息日数中。

【问题讨论】:

  • 我不太明白你想要什么,但我认为应该如下。你想知道几天后它会落在什么日期,不管周六和周日吗?例如,今天是 2020 年 6 月 11 日,您想知道 10 天内您一周中有多少天,即跳过周六和周日,即 2020 年 6 月 25 日
  • 会是这个吗?
  • 除了周六和周日还有假期
  • 好的,我知道了。我现在的问题与参数有关。第一个参数是日期,第二个参数是天数还是第二个日期?
  • 您需要明确添加天数的规则,包括开始天数和结束天数。星期五 + 1 是星期一吗?如果是这样,那么星期六 + 1 也是星期一(暂时忽略公共假期)?

标签: javascript date


【解决方案1】:

您的算法不正确,因为它计算了两个日期之间的休息天数,然后只是将它们添加到末尾,而不考虑添加的天数中包含更多的休息天数。

如果您想要实现的是在日期中添加营业日或工作日,请考虑只循环所需的天数,而忽略非工作日。

从您的评论看来,您希望 Fri + 1 是 Mon,但 Sat 或 Sun + 1 也是 Mon,所以我修改了代码,因此添加的开始日期除外:

  1. 星期五 + 1 是星期一
  2. 周五 + 2 是周二
  3. 星期六 + 1 是星期一

Fri + 0 是Fri,你也应该测试days的值,处理小于1的值。

我已经使周末和节假日的测试更有效率并简化了逻辑。

/** Add business days to a date
**  Non–working days: Sat and Sun and dates in hols array
**  First work day after start date is included in count, so
**    Fri + 1 => Mon
**    Fri + 2 => Tue
**    Sat + 1 => Mon
**  @param {Date} date - start date
**  @param {number} days - business days to add
**  @returns {Date}
**/
function addBusinessDays(date, days) {
  // Holiday array in YYYY-MM-DD format
  let hols = ['2020-07-14'];
  // Formatter for holiday array format
  let f = new Intl.DateTimeFormat('en-ca',{
    year: 'numeric',
    month: '2-digit',
    day: '2-digit'
  });
  // Copy date so don't modify original
  let d = new Date(+date);

  // Increment date required number of times
  while (days > 0) {
    d.setDate(d.getDate() + 1);
    // Only decrement count if it's not Sat or Sun or holiday
    days -= d.getDay() % 6 != 0 && !hols.includes(f.format(d));
  } 
  
  return d;
}

[[new Date(2020, 6, 2), 1], // Thu 02 Jul 2020 + 1 day  => Fri 03 Jul
 [new Date(2020, 6, 3), 1], // Fri 03 Jul 2020 + 1 day  => Mon 06 Jul
 [new Date(2020, 6, 3), 2], // Fri 03 Jul 2020 + 2 days => Tue 07 Jul
 [new Date(2020, 6, 4), 1], // Sat 04 Jul 2020 + 1 day  => Mon 06 Jul
 [new Date(2020, 6,13), 2], // Mon 13 Jul 2020 + 2 days => Thu 16 Jul (14 Jul is holiday)
 [new Date(2020, 6, 6),12], // Mon 06 Jul 2020 +12 days => Thu 23 Jul (14 Jul is holiday)
].forEach(arr => {
  console.log(`Start: ${arr[0].toDateString()} plus ${arr[1]} = ${addBusinessDays(...arr).toDateString()}`);
});

这种方法适用于小范围,但对于较长的范围,更复杂的算法可能更有效。

【讨论】:

  • 感谢您的回答,我在第一个算法中使用模数根据另一个 StackOverflow 主题的答案确定休假天数,但最后,它以我上面的脚本结束,根据您的解释,我确实了解可能是什么问题。您的回答很好,但考虑到 Sat+1 = Mon 和 Sun +1 = Mon 也需要设置结束日期,如果周五是假期,那么 Thu +1 = Mon,我昨天做了一些测试,但没有任何相关性。我会尝试改进您的答案,因为它似乎比我当前的脚本好得多。
  • @LightninWolf — 我已将 do..while 更改为 just while,以便反映您明确的要求。
猜你喜欢
  • 1970-01-01
  • 2012-01-13
  • 1970-01-01
  • 1970-01-01
  • 2014-12-11
  • 2020-03-21
  • 2013-11-13
  • 2010-12-01
  • 2020-11-20
相关资源
最近更新 更多