0

私は仕事が取るだろうと思い、開始日と時間数に基づいて、タスクの終了日を提供するために、Googleシートでカスタム関数を作成していため、カスタム関数の最大スタックの深さを超えています。は、Googleシート

つまり終了日=開始日+時間。

機能は、(私はランチタイムを除く土日祝日を指定するまで作業していて、良い時間内のすべてのよ)週末をスキップして、9と17時間の稼働日を考慮することを目指しています。

機能は、約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

こんにちはステファン、あなたの返事に感謝します。私はこれをより効率的にするアイデアには開放されています。そのため、再帰的な要素を取り除くことが必要です。私は「尾部再帰」が何であるかはわかりませんが、私が調べることができるものです。スタック深度は、私がこれを書いているGoogle Sheetsアプリケーションによって設定されていると思います。 – mulkraj

+0

こんにちはStefan、私は再帰の代わりにループを使用するようにコードを修正しました。私は今、Googleスプレッドシートに日付を追加する機能を持っています。復帰日です。ご助力ありがとうございます。 – mulkraj

答えて

0

ここに作業コードがあります。ランチタイムを含めるようにコードを追加しようとしたときに重大な問題に遭遇しましたが、これは私のロジックの欠陥を強調するために働いていました。これで、Googleスプレッドシートの[設定]という2番目のシートのランチタイムも考慮されるようになります。 (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; 
    }