如何使用 moment.js 添加天数(不包括周末)?

问题描述 投票:0回答:9

我设置了当前日期两天后的默认后续日期,目前有效:

const Notify = moment().add(2, 'days').toDate();

但是,我想排除周末。所以我安装了 moment WeekDay,但我似乎无法让它在当前日期中添加天数。该文档要求:

moment().weekday(0)

但是我无法在两天后添加它。有任何想法吗?

javascript node.js angular typescript momentjs
9个回答
18
投票

这个解决方案很简单,易于遵循,并且对我来说效果很好:

function addBusinessDays(originalDate, numDaysToAdd) {
  const Sunday = 0;
  const Saturday = 6;
  let daysRemaining = numDaysToAdd;

  const newDate = originalDate.clone();

  while (daysRemaining > 0) {
    newDate.add(1, 'days');
    if (newDate.day() !== Sunday && newDate.day() !== Saturday) {
      daysRemaining--;
    }
  }

  return newDate;
}

10
投票

尝试:时刻-工作日

应该对你有帮助。

示例:

var momentBusinessDays = require("moment-business-days")

momentBusinessDays('20-09-2018', 'DD-MM-YYYY').businessAdd(3)._d 

结果:

Tue Sep 25 2018 00:00:00 GMT+0530 (IST)

6
投票

您也可以不使用外部库并执行像这两个之一这样的简单功能:

const WEEKEND = [moment().day("Saturday").weekday(), moment().day("Sunday").weekday()]

const addBusinessDays1 = (date, daysToAdd) => {
  var daysAdded = 0,
    momentDate = moment(new Date(date));
  while (daysAdded < daysToAdd) {
    momentDate = momentDate.add(1, 'days');
    if (!WEEKEND.includes(momentDate.weekday())) {
      daysAdded++
    }
  }

  return momentDate;
}
console.log(addBusinessDays1(new Date(), 7).format('MM/DD/YYYY'))
console.log(addBusinessDays1('09-20-2018', 3).format('MM/DD/YYYY'))

// This is the somewhat faster version
const addBusinessDays2 = (date, days) => {
  var d = moment(new Date(date)).add(Math.floor(days / 5) * 7, 'd');
  var remaining = days % 5;
  while (remaining) {
    d.add(1, 'd');
    if (d.day() !== 0 && d.day() !== 6)
      remaining--;
  }
  return d;
};

console.log(addBusinessDays2(new Date(), 7).format('MM/DD/YYYY'))
console.log(addBusinessDays2('09-20-2018', 3).format('MM/DD/YYYY'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.2/moment.min.js"></script>

它们对这篇文章进行了稍微修改,我认为它们是您必须携带/处理的外部库的一个很好的替代方案(假设这是您唯一需要的部分,而不是该库的其他功能)。


2
投票

这将基于任何开始日期来执行此操作,并且没有昂贵的循环。您计算需要跳过的周末天数,然后将工作日和周末的天数一起抵消。

function addWeekdays(year, month, day, numberOfWeekdays) {
    var originalDate = year + '-' + month + '-' + day;
    var futureDate = moment(originalDate);
    var currentDayOfWeek = futureDate.day();            // 0 = Sunday, 1 = Monday, ..., 6 = Saturday
    var numberOfWeekends = Math.floor((currentDayOfWeek + numberOfWeekdays - 1) / 5);   // calculate the number of weekends to skip over

    futureDate.add(numberOfWeekdays + numberOfWeekends * 2, 'days');    // account for the 2 days per weekend

    return futureDate;
}

2
投票
const addWorkingDays = (date: Moment, days: number) => {
  let newDate = date.clone();
  for (let i = 0; i < days; i++) {
    if (newDate.isoWeekday() !== 6 && newDate.isoWeekday() !== 7) {
      newDate = newDate.add(1, "days");
    } else {
      newDate = newDate.add(1, "days");
      i--;
    }
  }
  return newDate.format("YYYY/MM/DD");
};

1
投票
var moment = require("moment")
function addWorkingDay(date, days){
    let daysToAdd = days
    const today = moment(date);
    const nextWeekStart = today.clone().add(1, 'week').weekday(1);
    const weekEnd = today.clone().weekday(5);

    const daysTillWeekEnd = Math.max(0, weekEnd.diff(today, 'days'));
    if(daysTillWeekEnd >= daysToAdd) return today.clone().add(daysToAdd, 'days');
    
    daysToAdd = daysToAdd - daysTillWeekEnd - 1;
    
    return nextWeekStart.add(Math.floor(daysToAdd/5), 'week').add(daysToAdd % 5, 'days')
}

0
投票

我认为这段代码会更快:

var businessDays = 10;
var days = businessDays + Math.floor((Math.min(moment().day(),5)+businessDays)/6)*2;
moment.add(days, 'days');

0
投票
// using pure JS

function addBusinessDays(originalDate, numDaysToAdd) {
  const Sunday = 0;
  const Saturday = 6;
  let daysRemaining = numDaysToAdd;

  const newDate = originalDate;

  while (daysRemaining > 0) {
   newDate.setDate(newDate.getDate() + 1);
    if (newDate.getDay() !== 0 && newDate.getDay() !== 6) {
    // skip sunday & saturday
      daysRemaining--;
    }
  }

  return newDate;
}

var dt = new Date(); // get date
var business_days = 8;

newDate = addBusinessDays(dt, business_days);


console.log(newDate.toString());

0
投票

评价最高的解决方案不太冗长,但使用循环一次添加天数,而不是提前计算要添加的日历天数。

已发布的其他解决方案尝试计算,但它们要么不起作用,要么存在无法处理的边缘情况(例如,如果原始日期恰好是周末怎么办?)

如果您想处理不同地区的假期并利用库的其他功能,那么使用“时刻工作日”的建议很好,但是(IMO)如果我们只是坚持 OP 的要求,即“添加 X 天,跳过周六和周日。”

无论如何,我最近不得不在一个项目中这样做,这是我想出的解决方案:

const addBusinessDaysToDate = (date, businessDays) => {
    // bit of type checking, and making sure not to mutate inputs :: 
    const momentDate = date instanceof moment ? date.clone() : moment(date);

    if (!Number.isSafeInteger(businessDays) || businessDays <= 0) {
        // handle these situations as appropriate for your program; here I'm just returning the moment instance :: 
        return momentDate;
    } else {
        // for each full set of five business days, we know we want to add 7 calendar days :: 
        const calendarDaysToAdd = Math.floor(businessDays / 5) * 7;
        momentDate.add(calendarDaysToAdd, "days");
        
        // ...and we calculate the additional business days that didn't fit neatly into groups of five :: 
        const remainingDays = businessDays % 5;
        
        // if the date is currently on a weekend, we need to adjust it back to the most recent Friday :: 
        const dayOfWeekNumber = momentDate.day();
        if (dayOfWeekNumber === 6) {
            // Saturday -- subtract one day :: 
            momentDate.subtract(1, "days"); 
        } else if (dayOfWeekNumber === 0) {
            // Sunday -- subtract two days :: 
            momentDate.subtract(2, "days");
        }

        // now we need to deal with any of the remaining days calculated above :: 
        if ((momentDate.day() + remainingDays) > 5) {
            // this means that adding the remaining days has caused us to hit another weekend; 
            // we must account for this by adding two extra calendar days :: 
            return momentDate.add(remainingDays + 2, "days");
        } else {
            // we can just add the remaining days :: 
            return momentDate.add(remainingDays, "days");
        }
    }
};

这是一个快速小测试脚本的结果:

_________________________________________
Original Date ::  2023-10-28
Plus  3  Business Days ::  2023-11-01
Plus  10  Business Days ::  2023-11-10
Plus  14  Business Days ::  2023-11-16
Plus  15  Business Days ::  2023-11-17
Plus  22  Business Days ::  2023-11-28

_________________________________________
Original Date ::  2023-10-29
Plus  3  Business Days ::  2023-11-01
Plus  10  Business Days ::  2023-11-10
Plus  14  Business Days ::  2023-11-16
Plus  15  Business Days ::  2023-11-17
Plus  22  Business Days ::  2023-11-28

_________________________________________
Original Date ::  2023-10-30
Plus  3  Business Days ::  2023-11-02
Plus  10  Business Days ::  2023-11-13
Plus  14  Business Days ::  2023-11-17
Plus  15  Business Days ::  2023-11-20
Plus  22  Business Days ::  2023-11-29

_________________________________________
Original Date ::  2023-10-31
Plus  3  Business Days ::  2023-11-03
Plus  10  Business Days ::  2023-11-14
Plus  14  Business Days ::  2023-11-20
Plus  15  Business Days ::  2023-11-21
Plus  22  Business Days ::  2023-11-30

_________________________________________
Original Date ::  2023-11-01
Plus  3  Business Days ::  2023-11-06
Plus  10  Business Days ::  2023-11-15
Plus  14  Business Days ::  2023-11-21
Plus  15  Business Days ::  2023-11-22
Plus  22  Business Days ::  2023-12-01

_________________________________________
Original Date ::  2023-11-02
Plus  3  Business Days ::  2023-11-07
Plus  10  Business Days ::  2023-11-16
Plus  14  Business Days ::  2023-11-22
Plus  15  Business Days ::  2023-11-23
Plus  22  Business Days ::  2023-12-04

_________________________________________
Original Date ::  2023-11-03
Plus  3  Business Days ::  2023-11-08
Plus  10  Business Days ::  2023-11-17
Plus  14  Business Days ::  2023-11-23
Plus  15  Business Days ::  2023-11-24
Plus  22  Business Days ::  2023-12-05
© www.soinside.com 2019 - 2024. All rights reserved.