在 Javascript 中计算假期

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32342753/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 15:08:29  来源:igfitidea点击:

calculate holidays in Javascript

javascript

提问by Steven Gregory

I created the following JavaScript to calculate holidays that are not fixed. It works it seems. My questions, though, are can it be written more efficiently and did I omit anything that would improve it?

我创建了以下 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

采纳答案by gilly3

Instead of that block of ifstatements, you should have a dictionary of holidays accessible with a key. Your function should just construct a key from the input and see if a holiday exists with that key.

if你应该有一个可以通过键访问的假期字典,而不是那块语句。您的函数应该只从输入中构造一个键,然后查看该键是否存在假期。

I would break out the functionality to find holidays and find dates into separate functions. You can then have a third function that returns a string representation of the date, including the holiday if any.

我会将查找假期和查找日期的功能分解为单独的函数。然后,您可以使用第三个函数返回日期的字符串表示形式,包括假期(如果有)。

Do every thing zero based. If you want the first occurrence of a day in the month, pass 0. To count from the end of the month, pass negative numbers indicating how many weeks to count back. So, for the last occurrence of a day in the month, pass -1. These changes make it easy to find a date using math.

做每一件事都以零为基础。如果您想在一个月中第一次出现某一天,请通过0。要从月底开始计数,请传递负数,指示要倒计时的周数。因此,对于一个月中最后一天出现的情况, pass -1。这些更改使使用数学查找日期变得容易。

The built-in Date.toLocaleDateString()already produces the date string you are looking for. You might consider using that instead. Either way, don't repeat the code that constructs the date string. Create the date string, then if there is a holiday, append it to the date string.

内置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;
}

回答by derekantrican

I had problems with @gilly3 's answer trying to use it with the current year (2019). Most of the holiday dates generated were off by about a week. So I adapted an answer from herethat works for me

我对@gilly3 的回答有问题,试图在当年(2019 年)使用它。生成的大部分假期日期都相差一周左右。所以我改编自一个答案这里是对我来说有效

Important thing to note about this version: instead of using "-1" for the last holiday of the month, it uses "5". And "week" is not longer zero-based (like gilly3's answer) but is "1-based" (like OP's original code)

关于此版本需要注意的重要事项:不是在本月的最后一个假期使用“-1”,而是使用“5”。并且“周”不再基于零(如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;
}

回答by Arjun Panickssery

Replace your rows of if statements with if-else.

用 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()));
}

This can definitely be changed to if-else.

这绝对可以更改为 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"; }

Also, use an if-else statement here.

此外,请在此处使用 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 + ' &nbsp;&nbsp;&nbsp;' + holiday;
}   

This will make your code more efficient, if only slightly.

这将使您的代码更高效,即使只是稍微。