我创建了以下JavaScript来计算未修复的假期。看起来很有效。但是,我的问题是,它是否可以更有效地编写,我是否省略了可以改善它的任何内容?
var year = new Date().getFullYear();
// lowercase is used
var first = 1,second = 2,third = 3,fourth = 4; // Which occurrence in a given month. If there ma be a fifth occurrence, use "last."
var last = 99; // Find last occurrence of weekday in a month. "last" set to "99".
// lowercase used for weekday names
var sun = 0,mon = 1,tue = 2,wed = 3,thu = 4,fri = 5,sat = 6; // JavaScript nubers weekdays 0 - 6 for Sundayear through Saturdayear.
var sunday = 0,monday = 1,tuesday = 2,wednesday = 3,thursday = 4,friday = 5,saturday = 6;
// lowercase used for month names
var jan = 0,feb = 1,mar =2 ,apr = 3 ,may = 4,jun = 5,jul = 6,aug = 7,sep = 8,oct = 9,nov=10,dec = 11; // JavaScript numbers months 0 - 11, not 1 - 12.
var january = 0,february = 1,march = 2,april = 3,may = 4,june = 5,july = 6,august = 7,september = 8,october = 9,november = 10,december = 11;
function findHoliday(occurrence,weekday,month,year) { // Find the 'first', 'second', 'third', 'fourth', or 'last' weekday occurrence in a given month and year.
/* Note: Numbers may be used instead of text.
occurrence = first; second; third; fourth; or last
weekday = sun; mon; tue; wed; thu; fri; or sat
month = jan; feb; mar; apr; mayear; jun; jul; aug; sep; oct; nov; or dec
year = year from the variable 'year', or a specific year may be used such as 1990, 2010, 2017, etc.
Syntax Examples: findHoliday(third,mon,jan,year) Martin Luther King, Jr. Dayear is US.
findHoliday(last,mon,mayear,2017) Memorial Day in US.
*/
/* The most efficient method to find the 'last' (or 5th, if it exists) occurrence of a Sun, Mon, Tue, Wed, Thu, Fri, or Sat in a month is to find its first
occurrence in the following month and then subtract 7 days from that date. That is what the following 'if' statement does.
*/
if (occurrence === 99) {
var theDate = new Date(year,month+1,1+((first - (weekday >= new Date(year,month+1,1).getDay())) * 7) + (weekday - new Date(year,month+1,1).getDay())-7);
}
// Finds the 'first', 'second', 'third', or 'fourth' occurrence of a weekday in a month.
if (occurrence !== 99) {
var theDate = new Date(year,month,1+((occurrence - (weekday >= new Date(year,month,1).getDay())) * 7) + (weekday - new Date(year,month,1).getDay()));
}
/* EDIT below to end of function to adapt to your needs */
var holiday = "";
if (occurrence == 3 && weekday == 1 && month == 0) { holiday = "Martin Luther King, Jr. Dayear"; }
if (occurrence == 2 && weekday == 1 && month == 1) { holiday = "President's Day"; }
if (occurrence == 2 && weekday == 0 && month == 2) { holiday = "Daylight Savings Time Begins"; }
if (occurrence == 4 && weekday == 3 && month == 3) { holiday = "Administrative Assistants Day"; }
if (occurrence == 2 && weekday == 0 && month == 4) { holiday = "Mother's Day"; }
if (occurrence == 99 && weekday == 1 && month == 4) { holiday = "Memorial Day"; }
if (occurrence == 3 && weekday == 0 && month == 5) { holiday = "Father's Day"; }
if (occurrence == 3 && weekday == 0 && month == 6) { holiday = "Parents Day"; }
if (occurrence == 1 && weekday == 1 && month == 8) { holiday = "Labor Day"; }
if (occurrence == 2 && weekday == 0 && month == 8) { holiday = "Grandparents Day"; }
if (occurrence == 99 && weekday == 0 && month == 8) { holiday = "Gold Star Mothers Day"; }
if (occurrence == 2 && weekday == 1 && month == 9) { holiday = "Columbus Day"; }
if (occurrence == 1 && weekday == 0 && month == 10) { holiday = "Daylight Savings Time Ends"; }
if (occurrence == 4 && weekday == 4 && month == 10) { holiday = "Thanksgiving Day"; }
var weekday = new Array("Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday");
var mMonth = new Array("January","February","March","April","May","June","July","August","September","October","November","December");
var displayDate = "";
if (holiday == ""){
var displayDate = weekday[theDate.getDay()] + ', ' + mMonth[theDate.getMonth()] + ' ' + theDate.getDate() + ', ' + year;
}
if (holiday != "") {
var displayDate = weekday[theDate.getDay()] + ', ' + mMonth[theDate.getMonth()] + ' ' + theDate.getDate() + ', ' + year + ' ' + holiday;
}
return displayDate;
} // End of 'findHoliday(o,d,m,year)' function
// Examples Only: Delete as is not part of this script.
document.write(findHoliday(third,sunday,june,year) + '<p>')
document.write(findHoliday(3,0,5,2015));
// End of Examples
答案 0 :(得分:3)
您应该使用密钥访问假日字典,而不是if
语句块。您的函数应该只是从输入构造一个键,并查看该键是否存在假日。
我会打破功能,找到假期,并在不同的功能中找到日期。然后,您可以使用第三个函数返回日期的字符串表示形式,包括假日(如果有的话)。
每件事都以零为基础。如果您想要在该月中第一次出现一天,请通过0
。要从月末开始计算,请传递负数,表示要计算多少周。因此,对于该月中某一天的最后一次出现,请通过-1
。这些更改使您可以轻松地使用数学查找日期。
内置Date.toLocaleDateString()
已生成您要查找的日期字符串。您可以考虑使用它。无论哪种方式,都不要重复构造日期字符串的代码。创建日期字符串,如果有假期,则将其附加到日期字符串。
var holidays = { // keys are formatted as month,week,day
"0,2,1": "Martin Luther King, Jr. Day",
"1,2,1": "President's Day",
"2,1,0": "Daylight Savings Time Begins",
"3,3,3": "Administrative Assistants Day",
"4,1,0": "Mother's Day",
"4,-1,1": "Memorial Day",
"5,2,0": "Father's Day",
"6,2,0": "Parents Day",
"8,0,1": "Labor Day",
"8,1,0": "Grandparents Day",
"8,-1,0": "Gold Star Mothers Day",
"9,1,1": "Columbus Day",
"10,0,0": "Daylight Savings Time Ends",
"10,3,4": "Thanksgiving Day"
};
function getDate(year, month, week, day) {
var firstDay = 1;
if (week < 0) {
month++;
firstDay--;
}
var date = new Date(year, month, (week * 7) + firstDay);
if (day < date.getDay()) {
day += 7;
}
date.setDate(date.getDate() - date.getDay() + day);
return date;
}
function getHoliday(month, week, day) {
return holidays[month + "," + week + "," + day];
}
function getDateString(year, month, week, day) {
var date = getDate(year, month, week, day);
var holiday = getHoliday(month, week, day);
var dateString = date.toLocaleDateString();
if (holiday) {
dateString += " \xa0\xa0\xa0" + holiday;
}
return dateString;
}
答案 1 :(得分:1)
如果您不需要计算假期,而只需要知道给定的一天是否是假期,则可以使用以下不使用任何库的简单javascript函数。
如果输入日期为假日,则此函数返回假日的名称,否则返回空字符串。
此解决方案满足我的以下要求:
。
function isBankHoliday(date) {
// static holidays
const isDate = (d, month, date) => {
return d.getMonth() == (month - 1) && d.getDate() == date;
};
if (isDate(date, 1, 1)) { return "New Year"; }
else if (isDate(date, 7, 4)) { return "Independence Day"; }
else if (isDate(date, 11, 11)) { return "Veterans Day"; }
else if (isDate(date, 12, 25)) { return "Christmas Day"; }
// dynamic holidays
const isDay = (d, month, day, occurance) => {
if (d.getMonth() == (month - 1) && d.getDay() == day) {
if (occurance > 0) {
return occurance == Math.ceil(d.getDate() / 7);
} else {
// check last occurance
let _d = new Date(d);
_d.setDate(d.getDate() + 7);
return _d.getMonth() > d.getMonth();
}
}
return false;
};
if (isDay(date, 1, 1, 3)) { return "MLK Day"; }
else if (isDay(date, 2, 1, 3)) { return "Presidents Day"; }
else if (isDay(date, 5, 1, -1)) { return "Memorial Day"; }
else if (isDay(date, 9, 1, 1)) { return "Labor Day"; }
else if (isDay(date, 10, 1, 2)) { return "Columbus Day"; }
else if (isDay(date, 11, 4, 4)) { return "Thanksgiving Day"; }
// Non Business days
if (date.getDay() == 0) { return "Sunday"; }
else if (date.getDay() == 6) { return "Saturday" }
// not a holiday
return "";
}
测试:
function isBankHoliday(date) {
// static holidays
const isDate = (d, month, date) => {
return d.getMonth() == (month - 1) && d.getDate() == date;
};
if (isDate(date, 1, 1)) { return "New Year"; }
else if (isDate(date, 7, 4)) { return "Independence Day"; }
else if (isDate(date, 11, 11)) { return "Veterans Day"; }
else if (isDate(date, 12, 25)) { return "Christmas Day"; }
// dynamic holidays
const isDay = (d, month, day, occurance) => {
if (d.getMonth() == (month - 1) && d.getDay() == day) {
if (occurance > 0) {
return occurance == Math.ceil(d.getDate() / 7);
} else {
// check last occurance
let _d = new Date(d);
_d.setDate(d.getDate() + 7);
return _d.getMonth() > d.getMonth();
}
}
return false;
};
if (isDay(date, 1, 1, 3)) { return "MLK Day"; }
else if (isDay(date, 2, 1, 3)) { return "Presidents Day"; }
else if (isDay(date, 5, 1, -1)) { return "Memorial Day"; }
else if (isDay(date, 9, 1, 1)) { return "Labor Day"; }
else if (isDay(date, 10, 1, 2)) { return "Columbus Day"; }
else if (isDay(date, 11, 4, 4)) { return "Thanksgiving Day"; }
// Non Business days
if (date.getDay() == 0) { return "Sunday"; }
else if (date.getDay() == 6) { return "Saturday" }
// not a holiday
return "";
}
console.log(isBankHoliday(new Date(2020, 00, 01)));
console.log(isBankHoliday(new Date(2020, 06, 04)));
console.log(isBankHoliday(new Date(2020, 10, 11)));
console.log(isBankHoliday(new Date(2020, 11, 25)));
console.log(isBankHoliday(new Date(2020, 00, 20)));
console.log(isBankHoliday(new Date(2020, 01, 17)));
console.log(isBankHoliday(new Date(2020, 04, 25)));
console.log(isBankHoliday(new Date(2020, 08, 07)));
console.log(isBankHoliday(new Date(2020, 09, 12)));
console.log(isBankHoliday(new Date(2020, 10, 26)));
console.log(isBankHoliday(new Date(2017, 00, 16)));
console.log(isBankHoliday(new Date(2017, 01, 20)));
console.log(isBankHoliday(new Date(2017, 04, 29)));
console.log(isBankHoliday(new Date(2017, 08, 04)));
console.log(isBankHoliday(new Date(2017, 09, 09)));
console.log(isBankHoliday(new Date(2017, 10, 23)));
// Weekends
console.log(isBankHoliday(new Date(2020, 0, 4)));
console.log(isBankHoliday(new Date(2020, 0, 12)));
// Negatives
console.log(isBankHoliday(new Date(2020, 00, 02)));
console.log(isBankHoliday(new Date(2020, 04, 18)));
console.log(isBankHoliday(new Date(2020, 04, 26)));
console.log(isBankHoliday(new Date(2017, 04, 22)));
console.log(isBankHoliday(new Date(2017, 04, 30)));
console.log(isBankHoliday(new Date(2017, 04, 31)));
console.log(isBankHoliday(new Date(2020, 0, 6)));
console.log(isBankHoliday(new Date(2020, 0, 8)));
console.log(isBankHoliday(new Date(2020, 0, 10)));
console.log(isBankHoliday(new Date(2020, 0, 31)));
答案 2 :(得分:0)
用if-else替换if语句行。
if (occurrence === 99) {
var theDate = new Date(year,month+1,1+((first - (weekday >= new Date(year,month+1,1).getDay())) * 7) + (weekday - new Date(year,month+1,1).getDay())-7);
}else{
var theDate = new Date(year,month,1+((occurrence - (weekday >= new Date(year,month,1).getDay())) * 7) + (weekday - new Date(year,month,1).getDay()));
}
这绝对可以改为if-else。
if (occurrence == 3 && weekday == 1 && month == 0) { holiday = "Martin Luther King, Jr. Dayear"; }
else if (occurrence == 2 && weekday == 1 && month == 1) { holiday = "President's Day"; }
else if (occurrence == 2 && weekday == 0 && month == 2) { holiday = "Daylight Savings Time Begins"; }
else if (occurrence == 4 && weekday == 3 && month == 3) { holiday = "Administrative Assistants Day"; }
else if (occurrence == 2 && weekday == 0 && month == 4) { holiday = "Mother's Day"; }
else if (occurrence == 99 && weekday == 1 && month == 4) { holiday = "Memorial Day"; }
else if (occurrence == 3 && weekday == 0 && month == 5) { holiday = "Father's Day"; }
else if (occurrence == 3 && weekday == 0 && month == 6) { holiday = "Parents Day"; }
else if (occurrence == 1 && weekday == 1 && month == 8) { holiday = "Labor Day"; }
else if (occurrence == 2 && weekday == 0 && month == 8) { holiday = "Grandparents Day"; }
else if (occurrence == 99 && weekday == 0 && month == 8) { holiday = "Gold Star Mothers Day"; }
else if (occurrence == 2 && weekday == 1 && month == 9) { holiday = "Columbus Day"; }
else if (occurrence == 1 && weekday == 0 && month == 10) { holiday = "Daylight Savings Time Ends"; }
else if (occurrence == 4 && weekday == 4 && month == 10) { holiday = "Thanksgiving Day"; }
此外,请在此处使用if-else语句。
if (holiday == ""){
var displayDate = weekday[theDate.getDay()] + ', ' + mMonth[theDate.getMonth()] + ' ' + theDate.getDate() + ', ' + year;
} else{
var displayDate = weekday[theDate.getDay()] + ', ' + mMonth[theDate.getMonth()] + ' ' + theDate.getDate() + ', ' + year + ' ' + holiday;
}
这将使您的代码更有效,如果只是轻微。
答案 3 :(得分:0)
@ gilly3的答案在尝试在当前年份(2019年)中使用时遇到问题。生成的大多数假期日期都约有一周的时间。因此,我改编了here个对我有用的答案
有关此版本的重要说明:在该月的最后一个假期中,它使用“ 5”代替,而不是使用“ -1”。而且“ week”不再是基于零的(如gilly3的答案),而是基于“ 1”的(如OP的原始代码)
var holidays = { // keys are formatted as month,week,day
"0,3,1": "Martin Luther King, Jr. Day", //3rd Mon in Jan
"1,3,1": "President's Day", //3rd Mon in Feb
"2,2,0": "Daylight Savings Time Begins", //2nd Sun in Mar
"3,3,3": "Administrative Professionals Day", //3rd Wed in Apr
"4,2,0": "Mother's Day", //2nd Sun in May (in the US, but not all countries)
"4,5,1": "Memorial Day", //Last Mon in May
"5,3,0": "Father's Day", //3rd Sun in Jun (in the US, but not all countries)
"6,4,0": "Parents Day", //4th Sun of Jul
"8,1,1": "Labor Day", //1st Mon in Sept
//"8,1,0": "Grandparents Day", //Technically this is the 1st Sun AFTER Labor Day
// so can't be represented perfectly this way
"8,5,0": "Gold Star Mothers Day", //Last Sun in Sep
"9,2,1": "Columbus Day", //2nd Mon in Oct
"10,1,0": "Daylight Savings Time Ends", //1st Sun in Nov
"10,4,4": "Thanksgiving Day" //4th Thurs in Nov
};
function getDate(year, month, week, day) {
var date = new Date(year, month, 1),
add = (day - date.getDay() + 7) % 7 + (week - 1) * 7;
// make sure that we stay in the same month
do {
date.setMonth(month);
date.setDate(1 + add);
add -= 7;
} while (date.getMonth() != month);
return date;
}
function getHoliday(month, week, day) {
return holidays[month + "," + week + "," + day];
}
function getDateString(year, month, week, day) {
var date = getDate(year, month, week, day);
var holiday = getHoliday(month, week, day);
var dateString = date.toLocaleDateString();
if (holiday) {
dateString += " \xa0\xa0\xa0" + holiday;
}
return dateString;
}
答案 4 :(得分:0)
这是使用Google搜索时排名第一的答案,但是IMO此解决方案不完整。我无法发表评论。
该解决方案不提供使用方法。不能按原样调用代码。
主要功能要求您提供星期,这是使用标准javascript方法(例如getFullYear()或getDay())无法获得的。
回答问题的人应提供一个可以调用的功能齐全的示例。
答案 5 :(得分:0)
我在寻找一种检测浮动假期的方法时遇到了这篇文章。我的初衷是在联邦假日和自定义日期隐藏页面上的某些元素。这是基于最佳重构实践的一些改进。我不会处理诸如新年或圣诞节之类固定日期的假期。
创建这些帮助程序似乎有点过多,但它们使事情变得更具可读性且易于遵循。我只包括联邦假日。
var SUN = 1,
MON = 2,
TUE = 3,
WED = 4,
THU = 5,
FRI = 6,
SAT = 7;
var JAN = 1,
FEB = 2,
MAR = 3,
APR = 4,
MAY = 5,
JUN = 6,
JUL = 7,
AUG = 8,
SEP = 9,
OCT = 10,
NOV = 11,
DEC = 12;
var FIRST = 1,
SECOND = 2,
THIRD = 3,
FOURTH = 4,
LAST = -1;
var HOLIDAYS = {
"Martin Luther King, Jr. Day": [THIRD, MON, JAN],
"Memorial Day": [LAST, MON, MAY],
"Labor Day": [FIRST, MON, SEP],
"Columbus Day": [SECOND, MON, OCT],
"Thanksgiving Day": [LAST, THU, NOV]
};
var isFloatingHoliday = function(date, occurrence, weekDay, month) {
if (date.getMonth() != month - 1) {
return false;
}
if (date.getDay() != weekDay - 1) {
return false;
}
var DAYS_IN_WEEK;
if (occurrence == Math.ceil(date.getDate() / DAYS_IN_WEEK)) {
return true;
}
var LAST = -1;
if (occurrence != LAST) {
return false;
}
var newDate = new Date(date);
newDate.setDate(date.getDate() + DAYS_IN_WEEK);
newDate.getMonth() + 1;
return month != newDate.getMonth() + 1;
};
var getFloatingHoliday = function(date) {
var results = Object.keys(HOLIDAYS).filter(function(val, index) {
var occurrence = HOLIDAYS[val][0];
var weekDay = HOLIDAYS[val][1];
var month = HOLIDAYS[val][2];
if (isFloatingHoliday(date, occurrence, weekDay, month)) {
return true;
}
return false;
});
if (results.length) {
return results[0];
}
return null;
}
console.log(isFloatingHoliday(new Date('5/25/2020'), LAST, MON, MAY)); // true
console.log(getFloatingHoliday(new Date('5/25/2020'))); // Memorial Day
console.log(isFloatingHoliday(new Date('11/26/2020'), LAST, THU, NOV)); // true
console.log(getFloatingHoliday(new Date('11/26/2020'))); // Thanksgiving Day
console.log(isFloatingHoliday(new Date('1/1/2020'), LAST, THU, NOV)); // false
console.log(getFloatingHoliday(new Date('1/1/2020'))); // null
这里做了几处改进
由于我们是人类,所以我们指的是从1开始的几个月,因此我选择创建助手来使假期的初始化更易于阅读。
个月从1开始
var JAN = 1,
FEB = 2,
MAR = 3,
APR = 4,
MAY = 5,
JUN = 6,
JUL = 7,
AUG = 8,
SEP = 9,
OCT = 10,
NOV = 11,
DEC = 12;
一周中的第一天开始
var SUN = 1,
MON = 2,
TUE = 3,
WED = 4,
THU = 5,
FRI = 6,
SAT = 7;
和事件
var FIRST = 1,
SECOND = 2,
THIRD = 3,
FOURTH = 4,
LAST = -1;
我将细分isFloatingHoliday每一步的逻辑
第一个条件检查月份是否匹配,如果不匹配 没有意义继续并返回false
if (date.getMonth() != month - 1) {
return false;
}
第二个条件检查星期几是否匹配,如果不匹配 没有意义继续并返回false
if (date.getDay() != weekDay - 1) {
return false;
}
第三个条件试图查找提供的日期属于哪种情况。在这一点上,我们知道代码中的日期和星期几正确。我们需要弄清楚的是当月发生的情况。 为此,您只需将日期除以7并四舍五入即可。
第一次-第一次出现7次
第8次-第14次发生
15日-21日第三次发生
第四十二次至第二十八次
第29次+第五次出现
如果给定的匹配项匹配,则无需检查任何内容,我们获得了正确的月份/日期和匹配项,返回true
if (occurrence == Math.ceil(date.getDate() / 7)) {
return true;
}
第四个条件指出了是否要检查以-1表示的LAST出现。如果不是,则意味着 出现的次数不匹配,因此返回false
if (occurrence != -1) {
return false;
}
第五部分将计算日期+ 7天,以查看它是否在同一个月内。如果是这样,则表示该日期不是最后一次出现,因此返回false。 但是,如果7天后的日期属于另一个月份,我们知道这实际上是最后一次出现,并且我们返回true
var newDate = new Date(date);
newDate.setDate(date.getDate() + 7);
return month != newDate.getMonth() + 1;
我将分解getFloatingHoliday每一步的逻辑
第一步是过滤掉我们在HOLIDAYS中定义的所有浮动假期。由于键是假期名称,而值是描述事件发生的数组 我们可以使用Object.keys将键提取到一个数组中,并逐个过滤。
Object.keys(HOLIDAYS)
.filter(function(val, index) {
...
});
在过滤器内部,我们将值提取为可读状态,然后使用现有的isFloatingHoliday(...)函数查看当前日期是否符合描述。如果没有,请继续下一步。
{
var occurrence = HOLIDAYS[val][0];
var weekDay = HOLIDAYS[val][1];
var month = HOLIDAYS[val][2];
if (isFloatingHoliday(date, occurrence, weekDay, month)) {
return true;
}
return false;
}
过滤器执行后,它将返回与HOLIDAY条件匹配的所有键,并将其存储在“结果”中。鉴于假期的性质,可以安全地假设任何给定的日期最多只能返回1个假期。 因此,如果有任何结果,我们将退还假日。如果不是,则返回null。
if (results.length) {
return results[0];
}
return null;
以下是一些可供您试用的示例
console.log(isFloatingHoliday(new Date('5/25/2020'), LAST, MON, MAY)); // true
console.log(getFloatingHoliday(new Date('5/25/2020'))); // Memorial Day
console.log(isFloatingHoliday(new Date('11/26/2020'), LAST, THU, NOV)); // true
console.log(getFloatingHoliday(new Date('11/26/2020'))); // Thanksgiving Day
console.log(isFloatingHoliday(new Date('1/1/2020'), LAST, THU, NOV)); // false
console.log(getFloatingHoliday(new Date('1/1/2020'))); // null
我以这篇文章为灵感来对此进行扩展。显示的示例是我用来创建一个库的实际实现,该库不仅用于检查节假日的日期,还用于在匹配时执行回调。