我在这里创建了一个具有重叠时间段的样本表。我想计算没有重叠的总持续时间。我见过公式,但它不适用于较大的数据集或仅适用于 Excel。
我在Stack Overflow中也找到了一个示例公式,但它不适用于更大的数据集或更长的持续时间。
=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)+ 行(间接(“1:”&ROUND((MAX(E2:E23)-MIN(D2:D23))*1440,0)))/1440-1/2880,C2:C23,I2,B2:B23,I1 )>0)+0)/60
首先,要计算时间差,假设您是手动计算,可以使用以下公式:
=(hour(D2)+ MINUTE(D2)/60)- (hour(C2)+ MINUTE(C2)/60)
要查找
overlapping time
,您可以使用 if
函数来执行此操作:
=IF(and(D4<E3,B4=B3),((HOUR(E3)+MINUTE(E3)/60) - (HOUR(D4)+MINUTE(D4)/60)) ,0)
在您的示例中,不重叠的总时间应为
5.5 hrs
减去 total time w overlapping minus total overlapping time
。我说得对吗?
=SUM(E:E)-SUM(F:F)
像这样的脚本将使用“间隙和岛”原则给出任务的净时间(不幸的是所有参考文献似乎都与 SQL 相关)。另请参阅 VBA 版本,以下内容改编自:
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;
}
这是整个脚本,能够传递数组(因此可以使用过滤器)并检查是否添加了非日期:
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;
}
因此您可以将过滤后的数据传递给它,如下所示:
=myfunction(filter(D2:E,B2:B=J1,C2:C=J2))
给出这个:
我的解决方案可以在这里找到:链接
我添加了隐藏列 K-M,在其中过滤数据,以便仅列出所选名称,然后按开始日期时间(降序)对数据进行排序。
这允许我检查每一行是否与其上方的行重叠(如果当前行在其上方的行开始之后结束,则存在重叠)。
Column N
计算重叠时间,因为您似乎也想要该信息。
Column O
通过计算有重叠的时间来计算无重叠的时间,如果上行在下行结束之前开始(存在重叠),则减去上行开始与结束中较小者之间的时间任意行的时间。
I3
和 I4
然后通过仅对从选定日期开始的行进行求和来计算“有重叠的时间”和“无重叠的时间”(分别)。
此外,我还添加了一个名称下拉选择,由隐藏的
Column P
提供,它会自动生成 Column B
中唯一名称的列表。
我希望有帮助。如果您需要任何其他帮助,请告诉我。
以下内容对我有用。允许根据某些指定的条件过滤列。我在 F1、G1、H1 和 I1 上使用了标准。可以根据需要更改。
=SUM(LET(startEndTimes, 过滤器(D$2:$E$22, (($B$2:$B$22=$F1) + ($B$2:$B$22=$G1) + ($B$2:$ B$22=$H1)) * (IFERROR(MONTH($C$2:$C$22)=MONTH(I$1),0))), 序列, MIN($D$2:$D$22) + SEQUENCE(ROUNDUP( (最大值($E$2:$E$22) - 最小值($D$2:$D$22)) * 24 * 60, 0), 1, 1)/1440, IFERROR(MAP(序列, LAMBDA(x, IF( OR(MMULT(IFERROR((x >= INDEX(startEndTimes, , 1)) * (x <= INDEX(startEndTimes, , 2)), 0), 1) > 0), 1, 0))), REPT(0, ROWS(序列)))))/60