一、获取节假日数据
1.1 手动收集
通过官网通知获取节假日信息,手动收集
下面为个人收集的2020年假节日-调休数据,可直接使用
注意:放假情况可能会因特殊情况做出调整,记得及时更新
/**
* description: 2020年假期-调休数据 status-1放假, -2调休(工作日)
* 更新时间:2020-09-28
* author: dzd
*/
export const holidayArr = [
// 2020年
// 元旦
{"date":"2020-1-1","status":"1"},
// 春节
{"date":"2020-1-24","status":"1"},{"date":"2020-1-25","status":"1"},{"date":"2020-1-26","status":"1"},
{"date":"2020-1-27","status":"1"},{"date":"2020-1-28","status":"1"},{"date":"2020-1-29","status":"1"},
{"date":"2020-1-30","status":"1"},{"date":"2020-1-31","status":"1"},{"date":"2020-2-1","status":"1"},
{"date":"2020-2-2","status":"1"},{"date":"2020-1-19","status":"2"},
// 清明节
{"date":"2020-4-4","status":"1"},{"date":"2020-4-5","status":"1"},{"date":"2020-4-6","status":"1"},
// 劳动节
{"date":"2020-5-1","status":"1"},{"date":"2020-5-2","status":"1"},{"date":"2020-5-3","status":"1"},
{"date":"2020-5-4","status":"1"},{"date":"2020-5-5","status":"1"},{"date":"2020-4-26","status":"2"},
{"date":"2020-5-9","status":"2"},
// 端午节
{"date":"2020-6-25","status":"1"},{"date":"2020-6-26","status":"1"},{"date":"2020-6-27","status":"1"},
{"date":"2020-6-28","status":"2"},
// 国庆节、中秋节
{"date":"2020-10-1","status":"1"},{"date":"2020-10-2","status":"1"},{"date":"2020-10-3","status":"1"},
{"date":"2020-10-4","status":"1"},{"date":"2020-10-5","status":"1"},{"date":"2020-10-6","status":"1"},
{"date":"2020-10-7","status":"1"},{"date":"2020-10-8","status":"1"},{"date":"2020-9-27","status":"2"},
{"date":"2020-10-10","status":"2"}
];
2、通过其他公开Api获取
百度万年历节接口:https://sp0.baidu.com/8aQDcjqpAAV3otqbppnN2DJv/api.php?query=202010&resource_id=6018,其中
query=年[月]
,如202010
·`,月份为空默认为01
返回结构如下:
{
// 当前查询年月
OriginQuery: "202010",
// 本月日历
almanac: [],
// 本年节假日及调休数据
holiday: [
{
// 节假日起始日
festival: "2020-10-1",
// 节假日期list
list: [
date: "2020-10-1",
// 节假日-'1',调休(工作日)-'2'
status: "1"
]
}
// ...
],
// 本年节假
holidaylist: []
}
提取所有节假日期和调休
let holidayArr = []
// response - 上面接口返回的数据
const temp1 = response.data[0].holiday
temp1.forEach(item => {
// 已添加的不必重复
if (holidayArr.findIndex(hasItem => hasItem.date === item.festival) !== -1) {
return
}
item.list.forEach(dateItem => {
holidayArr.push({...dateItem, des: `${item.name}:${item.desc}`})
})
})
通过以上操作可获取结构为[{date: '2020-01-01', status: '1'}]
的数组holidayArr
,其中status = 1-节假日、2 - 工作日,如下图:
二、相关算法
2.1 判断一个日期是假期还是工作日
首先判断日期是否在
holidayArr
中,在里面就根据status
可以确定,不在里面再根据是否为周末判断,如下图:
// 收集到的节假/调休日期
const holidayArr = [];
// 是否为工作日 dateParam - Date | String
const isWorkDay = (dateParam) => {
let date = null;
const result = {
check: 1, // 是否正常判断
value: false,
warningMsg: '' // check=0时提示信息
}
if (dateParam instanceof Date) {
date = dateParam;
} else if (typeof dateParam === 'string') {
date = new Date(dateParam);
} else {
result.check = 0;
result.warningMsg = '暂不支持其他格式解析!';
return result
}
const year = date.getFullYear();
// 这里根据年份支持情况调整
if (year !== 2020) {
result.check = 0;
result.warningMsg = '暂时仅支持2020年工作日判断!';
return result
}
const dateStr = `${year}-${date.getMonth() + 1}-${date.getDate()}`;
const dateItem = holidayArr.find(item => {
return item.date === dateStr;
})
if (dateItem !== undefined) {
// 1-节假日,2-工作日
result.value = dateItem.status === '2';
return result
}
// 判断是否为周末,week表示日期对象的星期中的第几天(0-6)
const week = date.getDay();
result.value = week.toString().match(/[1-5]/) !== null;
return result
}
const result = isWorkDay('2020-09-27');
console.log((result.check === 1 && result.value) || result.warningMsg); // true
2.2 计算n个工作日后的日期
使用比较笨的方法,传入值依次添加 1 天,判断为工作日则累计值
m
(默认0)加 1 ,直到n === m
如2020-09-27,增加1个工作日为2020-09-28,增加5个工作日后为2020-10-10
注:计算范围必须在节假日时间范围内,比如此例子计算范围为2020年整年,若计算结果可能不在2020年,则不会准确。可通过添加holidayArr
子项解决此问题
// 获取经过n个工作日后日期 dateParam - Date | String, n - Number | String
const getAddWorkDayDate = (dateParam, addNum) => {
// addNum为数字或数字符串,负数表示经过addNum天到达传入dateParam,返回之前的日期
const addNumType = typeof addNum;
if (addNumType.match(/string|number/) === null || isNaN(addNum)) {
console.warn('计算参数传参格式有误!');
return ''
}
const num = Number.parseInt(addNum, 10);
// tag - true(正向日期计算),- false(反向计算)
const tag = num > 0;
// 增加或减少的工作日
let calcDay = Math.abs(num);
// 返回日期,初始值为传入值
let date = null;
if (dateParam instanceof Date) {
date = dateParam;
} else if (typeof dateParam === 'string') {
date = new Date(dateParam);
} else {
console.log('暂不支持其他格式解析!');
return ''
}
while (calcDay) {
let curDay = date.getDate();
date.setDate(tag ? (curDay + 1) : (curDay - 1));
// 判断是否为工作日
const result = isWorkDay(date);
if (result.value) {
calcDay--;
}
}
const dateStr = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
return dateStr;
}
console.log(getAddWorkDayDate('2020-09-27', 1)); // 2020-09-28
console.log(getAddWorkDayDate('2020-09-27', 5)); // 2020-10-10
console.log(getAddWorkDayDate('2020-09-27', -5)); // 2020-9-21
2.2 计算2个日期之间的工作日数
有时间再写,原理跟上面步骤类似。。