0

I created a sample sheet here that has overlapping time periods. I wanted to calculate the total duration without overlaps. I have seen formulas, but it doesn't work with larger data sets or only works in Excel.

I have a sample formula here that I found in Stack Overflow as well, but it doesn't work with a larger data set or longer durations.

=SUMPRODUCT((COUNTIFS(D2:D23,"<"&MIN(D2:D23)+ ROW(INDIRECT("1:"&ROUND((MAX(E2:E23)-MIN(D2:D23))*1440,0)))/1440-1/2880, E2:E23,">"&MIN(D2:D23)+ ROW(INDIRECT("1:"&ROUND((MAX(E2:E23)-MIN(D2:D23))*1440,0)))/1440-1/2880,C2:C23,I2,B2:B23,I1)>0)+0)/60

Enter image description here

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
JamesBowery
  • 71
  • 10

3 Answers3

1

First, to calculate the time difference, you may use the following formula assuming you are calculating it manually:

=(hour(D2)+ MINUTE(D2)/60)- (hour(C2)+ MINUTE(C2)/60)

To find the overlapping time, you can use the if function to do so:

=IF(and(D4<E3,B4=B3),((HOUR(E3)+MINUTE(E3)/60) - (HOUR(D4)+MINUTE(D4)/60)) ,0)

In your example, the total time without overlapping should be 5.5 hrs by substracting the total time w overlapping minus total overlapping time. Am I correct?

=SUM(E:E)-SUM(F:F)

Enter image description here

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Kin Siang
  • 2,644
  • 2
  • 4
  • 8
  • Sometimes the start and end time overlaps with more than 3 activities. Also, I added criteria/filters such as date and name. So I don't think this works. But thanks for this! – JamesBowery Jun 24 '21 at 05:38
  • It can always be calculated, although I not sure about your overlapping of three activities, both if involve `name and date`, you can add one more condition on the `if statement` will do – Kin Siang Jun 24 '21 at 06:03
0

A script like this will give the net time on a task using the 'gap and island' principle (unfortunately all references seem to relate to SQL). See also the VBA version of this which the following is adapted from:

function myFunction(prange) {

    var p = sheet.getRange(prange);

    var array = p.getValues();

    // Sort on start time

    array.sort(function(a, b) {
        return a[0] - b[0];
    })

    // Initialise

    minStart = array[0][0];
    maxEnd = array[0][0];
    gap = 0

    // Loop over rows

    for (i = 0; i<array.length;i++)
    {
        // If there is a gap, increment total gap length

        if (array[i][0] > maxEnd )
            gap = gap + array[i][0].valueOf() - maxEnd;

        // Update latest end time

        if (array[i][1] > maxEnd)
            maxEnd = array[i][1];
    }

    TimeOnTask = (maxEnd - minStart - gap)/(60*60*1000);

    return TimeOnTask;
}

Enter image description here

Here is the whole script with ability to pass an array (so filter can be used) and checking for non-dates added:

function myFunction(param) {
    var sheet = SpreadsheetApp.getActiveSpreadsheet();

    var r,array;
    if(typeof param =="string")
    {
      r = sheet.getRange(param);
      array = r.getValues();
    }
    else
      array=param;

    //Check for non-dates

    filteredArray = array.filter(function(value) {
      return Object.prototype.toString.call(value[0]) == "[object Date]" && Object.prototype.toString.call(value[1]) == "[object Date]";
    });

    // Sort the array

    filteredArray.sort(function(a, b) {
      return a[0] - b[0];
    })

    // Initialise

    minStart = filteredArray[0][0];
    maxEnd = filteredArray[0][0];
    gap = 0
    
    // Loop over rows

    for (i = 0; i<filteredArray.length;i++)
    {

      // If there is a gap, increment total gap length
    
      if (filteredArray[i][0] > maxEnd )
        gap = gap + filteredArray[i][0].valueOf() - maxEnd;

      // Update latest end time
        
      if (filteredArray[i][1] > maxEnd)
        maxEnd = filteredArray[i][1];
            
    }
    
    
    TimeOnTask = (maxEnd - minStart - gap)/(60*60*1000);


    return TimeOnTask;
}

So you can pass it the filtered data like this:

=myfunction(filter(D2:E,B2:B=J1,C2:C=J2))

to give this:

Enter image description here

Tom Sharpe
  • 30,727
  • 5
  • 24
  • 37
  • I revised the data sets with multiple criteria such as Employee Name and Date. How can I implement that in this script? thanks – JamesBowery Jun 24 '21 at 05:26
  • Maybe filter the dates in the script, or might be easier rather than having lots of versions of the script to filter the dates before passing them to the script. Will have a look at it. – Tom Sharpe Jun 24 '21 at 07:32
  • Thanks for the edit @Peter Mortensen - appreciate that the indentation wasn't very good. I have an update to the program to add some basic checks, but will try and keep to your layout changes. This is helpful to me because although I have a Java background, I'm still finding my way around Google scripts. – Tom Sharpe Jun 24 '21 at 15:47
0

My solution is available here: Link

I added hidden columns K-M where I filter the data so only the selected name is listed, then sort the data by start date-time (descending).

This allows me to check each row for overlapping with the row above it (if the current row ends after the row above it begins, there's an overlap).

  • Column N calculates the time with overlap since you seem to want that info as well.

  • Column O calculates the time without overlap by calculating the time with overlap and, if the upper row began before the lower row ended (an overlap exists), subtracting the time between the start of the upper row and the smaller of the ending times of either row.

I3 & I4 then calculate Time w/ Overlap and Time w/o Overlap (respectively) by summing only the rows that begin on the selected date.

In addition, I added a dropdown selection for the names, fed by hidden Column P, which simply automatically generates a list of the unique names in Column B.

I hope that helps. Please let me know if you need any additional help.

Gass
  • 7,536
  • 3
  • 37
  • 41
Matan Arie
  • 51
  • 5