【发布时间】:2017-04-05 23:06:49
【问题描述】:
如何使用 JavaScript 添加工作日(即周一至周五)在必要时自动添加周末?
因此,如果我要在今天(2016 年 11 月 22 日星期二)加上 5 个工作日,结果应该是“2016 年 11 月 29 日星期二”而不是“2016 年 11 月 27 日星期日”。
【问题讨论】:
标签: javascript
如何使用 JavaScript 添加工作日(即周一至周五)在必要时自动添加周末?
因此,如果我要在今天(2016 年 11 月 22 日星期二)加上 5 个工作日,结果应该是“2016 年 11 月 29 日星期二”而不是“2016 年 11 月 27 日星期日”。
【问题讨论】:
标签: javascript
可以使用Date 的setDate 函数(结合getDate)在日期上添加天数,即-
var myDate = new Date(); // Tue 22/11/2016
myDate.setDate(myDate.getDate() + 3); // Fri 25/11/2016
因此,一旦您计算出工作日期间的周末天数,您就可以将其和所需的工作日数添加到开始日期以获得最终日期。
这个功能应该可以工作,但显然这不会考虑到国定假日 -
function addWorkDays(startDate, days) {
if(isNaN(days)) {
console.log("Value provided for \"days\" was not a number");
return
}
if(!(startDate instanceof Date)) {
console.log("Value provided for \"startDate\" was not a Date object");
return
}
// Get the day of the week as a number (0 = Sunday, 1 = Monday, .... 6 = Saturday)
var dow = startDate.getDay();
var daysToAdd = parseInt(days);
// If the current day is Sunday add one day
if (dow == 0)
daysToAdd++;
// If the start date plus the additional days falls on or after the closest Saturday calculate weekends
if (dow + daysToAdd >= 6) {
//Subtract days in current working week from work days
var remainingWorkDays = daysToAdd - (5 - dow);
//Add current working week's weekend
daysToAdd += 2;
if (remainingWorkDays > 5) {
//Add two days for each working week by calculating how many weeks are included
daysToAdd += 2 * Math.floor(remainingWorkDays / 5);
//Exclude final weekend if remainingWorkDays resolves to an exact number of weeks
if (remainingWorkDays % 5 == 0)
daysToAdd -= 2;
}
}
startDate.setDate(startDate.getDate() + daysToAdd);
return startDate;
}
//And use it like so (months are zero based)
var today = new Date(2016, 10, 22);
today = addWorkDays(today, 5); // Tue Nov 29 2016 00:00:00 GMT+0000 (GMT Standard Time)
它也可以添加到Date原型中-
Date.prototype.addWorkDays = function (days) {
if(isNaN(days)) {
console.log("Value provided for \"days\" was not a number");
return
}
// Get the day of the week as a number (0 = Sunday, 1 = Monday, .... 6 = Saturday)
var dow = this.getDay();
var daysToAdd = parseInt(days);
// If the current day is Sunday add one day
if (dow == 0) {
daysToAdd++;
}
// If the start date plus the additional days falls on or after the closest Saturday calculate weekends
if (dow + daysToAdd >= 6) {
//Subtract days in current working week from work days
var remainingWorkDays = daysToAdd - (5 - dow);
//Add current working week's weekend
daysToAdd += 2;
if (remainingWorkDays > 5) {
//Add two days for each working week by calculating how many weeks are included
daysToAdd += 2 * Math.floor(remainingWorkDays / 5);
//Exclude final weekend if the remainingWorkDays resolves to an exact number of weeks
if (remainingWorkDays % 5 == 0)
daysToAdd -= 2;
}
}
this.setDate(this.getDate() + daysToAdd);
};
//And use it like so (months are zero based)
var today = new Date(2016, 10, 22)
today.addWorkDays(5); // Tue Nov 29 2016 00:00:00 GMT+0000 (GMT Standard Time)
【讨论】:
return this.addDays(daysToAdd); 而不是this.setDate(this.getDate() + daysToAdd);,因为它更类似于原生Date.prototype.addDays 的工作方式。
Date.prototype.addDays?我不知道原生的 addDays 方法,并且它没有记录在 MDN - developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… 上;您确定它没有被您的解决方案中的另一个 JS 文件添加吗?
我认为你可以使用moment-business-days。
例子:
// 22-11-2016 is Tuesday, DD-MM-YYYY is the format
moment('22-11-2016', 'DD-MM-YYYY').businessAdd(5)._d // Tue Nov 29 2016 00:00:00 GMT-0600 (CST)
【讨论】:
如果是添加几天,而不是几千天,那么这更容易且更具可读性:
const currentDate = new Date('2021-11-18');
console.log(currentDate.toString()); // "Thu Nov 18 2021 00:00:00 GMT+0000"
const numToAdd = 5;
for (let i = 1; i <= numToAdd; i++) {
currentDate.setDate(currentDate.getDate() + 1);
if (currentDate.getDay() === 6) {
currentDate.setDate(currentDate.getDate() + 2);
}
else if (currentDate.getDay() === 0) {
currentDate.setDate(currentDate.getDate() + 1);
}
}
console.log(currentDate.toString()); // "Thu Nov 25 2021 00:00:00 GMT+0000"
【讨论】:
const date = new Date('2000-02-02')
const daysToAdd = mapToWorkdays(date, 37)
date.setUTCDate(date.getUTCDate() + daysToAdd)
console.log( date.toISOString().split('T')[0] )
// prints 2000-03-24
/**
* @param {Date} date starting date
* @param {number} add number of workdays to add
* @return {number} total number of days to add to reach correct date
*/
function mapToWorkdays(date, add) {
const wd = weekday(date)
let r = Math.trunc(add / 5) * 2
const rem = add % 5
if (wd > 4) r += (6-wd)
else if (wd+rem > 4) r += 2
return add + r
}
/**
* @param {Date} date
* @return {number} day of the week in range of 0..6 (monday..sunday)
*/
function weekday(date) { return (date.getUTCDay()+ 6) % 7 }
【讨论】:
r += (7 - wd)。如果您从 sat/sun 调用该函数并传递 add:0,则结果仍应在星期六返回 2,在星期日返回 1。第一个 if 实际上是在说:“如果我们在周末,请将所有内容调整为一周的第一天(a.k.a 0)”。并且 else-if 说:“如果我们在工作日,并且 add%5 我们将在周末结束,我们应该再增加两天”
更新了上面的脚本,如果给出负数,也会减去工作日...
function addWorkDays(startDate, days) {
var isAddingDays = (days > 0);
var isDaysToAddMoreThanWeek = (days > 5 || days < -5);
if (isNaN(days)) {
console.log("Value provided for \"days\" was not a number");
return
}
if (!(startDate instanceof Date)) {
console.log("Value provided for \"startDate\" was not a Date object");
return
}
var dow = startDate.getDay();
var daysToAdd = parseInt(days);
if ((dow === 0 && isAddingDays) || (dow === 6 && !isAddingDays)) {
daysToAdd = daysToAdd + (1 * (isAddingDays ? 1 : -1));
} else if ((dow === 6 && isAddingDays) || (dow === 0 && !isAddingDays)) {
daysToAdd = daysToAdd + (2 * (isAddingDays ? 1 : -1));
}
if (isDaysToAddMoreThanWeek) {
daysToAdd = daysToAdd + (2 * (Math.floor(days / 5)));
if (days % 5 != 0)
daysToAdd = daysToAdd + (2 * (isAddingDays ? -1 : 1));
}
startDate.setDate(startDate.getDate() + daysToAdd);
var newDate = moment(startDate).format('MM/DD/YYYY');
return newDate;
}
【讨论】: