超出Google表格自定义功能中的最大堆栈深度

时间:2016-05-23 19:10:51

标签: javascript recursion google-apps-script google-sheets

我正在Google表格中创建自定义功能,根据开始日期和我认为该任务将需要的小时数来提供任务的结束日期。

即。结束日期=开始日期+小时。

该功能旨在跳过周末,并考虑在下午9点到5点之间的工作日(我正在努力排除午餐时间,指定周末和假期,但所有时间都很合适)。

该函数适用于大约五个活动,但随后出现错误“超出最大堆栈深度”。这是我所指的截图。

enter image description here

这是AppScript / JavaScript。

//var startdate = new Date(2016, 04, 16, 9, 0, 0);
//var addhours = 3;

Date.prototype.addHours = function(h) {
  this.setHours(this.getHours() + h);
  return this;
}

Date.prototype.addDays = function(days) {
  var dat = new Date(this.valueOf());
  dat.setDate(dat.getDate() + days);
  return dat;
}

/**
 * Adds hours to a date excludes weekends
 *
 * @param {number} startdate The date to add the hours to
 * @param {number} addHours The hours to add
 * @return The new date
 * @customfunction
 */

function MYWORKDAY(startdate, addhours) {
  var endDate = new Date();
  var endTime = new Date(startdate).setHours(17, 0, 0);
  var remainingEffortHrs = new Date();
  var availableTimeHrs = endTime - startdate;
  availableTimeHrs = (availableTimeHrs / 1000) / 60 / 60;

  if (startdate.map) { // Test whether input is an array.
    return startdate.map(MYWORKDAY); // Recurse over array if so.
  } else {

    // Add the hours to the start date
    //endDate = new Date(startdate).addHours(addhours);
    endDate = new Date(startdate).addHours(addhours);

    // Calculate remaining effort - if the task ends after 5pm
    if (endDate > endTime) {
      remainingEffortHrs = ((Math.abs(endDate - endTime)) / 1000) / 60 / 60;
    } else {
      remainingEffortHrs = 0;
    }

    if (remainingEffortHrs > 0) {
      startdate = new Date(startdate).addDays(1);
      startdate = MYWORKDAY(startdate, remainingEffortHrs);
    } else {
      // Remaining effort is 0
      startdate = endDate;
    }
    return GetNextWorking(startdate);
  }
}

function GetNextWorking(endDate) {
  // Get the next working day
  if (endDate.getDay() != 0 && endDate.getDay() != 6) {
      return endDate;
  } else {
    adjustedEndDate = new Date(endDate.setDate(endDate.getDate() + 1));
    adjustedEndDate = new Date(adjustedEndDate);
    // Recursively call the this function until the returned
    // date is a working day
    return adjustedEndDate = GetNextWorking(adjustedEndDate);
  }
}

我希望这是有道理的。这需要一段时间才能达到这个阶段,任何有关如何改进性能或重构的建议都将受到高度赞赏。

1 个答案:

答案 0 :(得分:0)

这是工作代码。在尝试添加代码以包括午餐时间时遇到了一些严重问题,但这有助于突出我逻辑中的缺陷。现在,这应考虑到Google表格中名为“设置”的第二张表格中的午餐时间。 (在Google表格之外工作时,我还没有完全解决如何绕过参考错误)。但这确实解决了超出最大堆栈深度错误。也许你可以建议改进?

 var dayStartTime = getStartTime();

 var dayEndTime = getEndTime();

 var lunchtimeEnd = getLunchtimeEnd();

 var lunchtimeStart = getLunchtimeStart();


  /* Starts the next day
   *
   * @param {number} startdate The date to add the hours to
   * @return The new date
   * @customfunction
   */

  Date.prototype.addDays = function(days) {
    var dat = new Date(this.valueOf());
    dat.setDate(dat.getDate() + days);
    return dat;
  }

  function addHours(date, h) {
     return new Date(date.getTime()  + (h*60*60*1000));
  }


    function MYWORKDAY(startdate,effort) {
    if (startdate.map) { 
      return startdate.map(MYWORKDAY); 
    } else {

      var endTime = new Date();

      var availableTimeHrs;

      var endDate = 0;

      while (effort > 0) 
      {
        endTime = new Date(startdate).setHours(dayEndTime.getHours(), dayEndTime.getMinutes(), dayEndTime.getSeconds());

        lunchtimeEnd = todaysLunchEnd(startdate);

        lunchtimeEnd = new Date(lunchtimeEnd);  

        lunchtimeStart = todaysLunchEnd(startdate);

        lunchtimeStart = new Date(lunchtimeStart);  

        endDate = addHours(startdate, effort);

        if (startdate <= lunchtimeStart && endDate >= lunchtimeEnd) {
           endDate = addHours(endDate, 1);
        } 

        if(endDate > endTime)
        {
          effort = ((Math.abs(endDate - endTime)) / 1000) / 60 / 60;   
          startdate = new Date(startdate).addDays(1);
          startdate = GetNextWorking(startdate);
          startdate = new Date(startdate).setHours(dayStartTime.getHours(), dayStartTime.getMinutes(), dayStartTime.getSeconds());
          startdate = new Date(startdate);

        } 
        else
        {
            effort = 0;
        }
      }
     }
     return endDate;
  }

  function GetNextWorking(endDate) {
     if (endDate.getDay() != 0 && endDate.getDay() != 6) {
      return endDate;
    } else {
      adjustedEndDate = new Date(endDate.setDate(endDate.getDate() + 1));
      adjustedEndDate = new Date(adjustedEndDate);
      return adjustedEndDate = GetNextWorking(adjustedEndDate);
    }
  }

  function MYSTARTDATE(startdate) {

    //var startTime = getStartTime();

    var morningStart = new Date();

    if (startdate.getHours() == 17) {
      morningStart = startdate.addDays(1);
      morningStart = GetNextWorking(morningStart);
      morningStart.setHours(9);
    } else {
      morningStart = startdate;
    }
    return morningStart;
  }

  function todaysLunchEnd(endDate) {
    var lunchtimeEnd = getLunchtimeEnd();

    lunchtimeEnd = new Date(endDate).setHours(lunchtimeEnd.getHours(), lunchtimeEnd.getMinutes(), lunchtimeEnd.getSeconds());
    lunchtimeEnd = new Date(lunchtimeEnd);
    return lunchtimeEnd;
  }

function getStartTime() {

    var settingsSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Settings");
    var range = settingsSheet.getRange("B5");
    var startTime = range.getValue(); 
    var startTime;

    if (!startTime) {
      startTime = new Date(28800000);
      //startTime = new Date(32400000); // 09:00
     }

    return startTime;
  }

  function getEndTime() {
    var settingsSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Settings");
    var range = settingsSheet.getRange("B6");
    var endTime = range.getValue(); 

    if (!endTime) {
       endTime = new Date(57600000);
       //endTime = new Date(61200000); // 17:00      
    }

    return endTime;
  }

  function getLunchtimeStart() {
    var settingsSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Settings");
    var range = settingsSheet.getRange("B7");
    var startTime = range.getValue(); 

    if (!startTime) {
      startTime = new Date(39600000); //11am
       //startTime = new Date(43200000); // 12pm
    }
    return startTime;
  }

  function getLunchtimeEnd() {
    var settingsSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Settings");
    var range = settingsSheet.getRange("B8");
    var endTime = range.getValue(); 

    if (!endTime) {
      endTime = new Date(43200000); //12:00
      //endTime = new Date(46800000); //13:00
    }

    return endTime;
  }