How to Exclude Overlapping Time Durations

I’m trying to calculate the total working hours from a list of tasks in my Glide app. Each task has a start time, end time, and duration. I use a Rollup column to sum up the total duration of all tasks.

The challenge is that some tasks overlap in time, and I want to ensure that overlapping durations are not double-counted in the total. For example:

• Task 1: 9:00 AM - 11:00 AM

• Task 2: 10:30 AM - 12:00 PM

In this case, the total working time should be 3 hours (not 3.5 hours).

Here’s what I’ve done so far:

  1. I created a relation to group tasks that occur on the same day.

Here I stuck.
I can’t figure out how to compare the start and end times of tasks within the same group to calculate overlapping durations.
Any advice or best practices would be greatly appreciated!
Thanks, Andi

Could you provide a screen shot of your table setup?

My solution looks like this.

Two columns to calculate the numeric value of start datetime & end datetime.

YEAR(D)*10^8+MONTH(D)*10^6+DAY(D)*10^4+HOUR(D)*10^2+MINUTE(D)

A query to get all tasks from the same day.

A JS column to get the numerical values of start and end datetime, and return a list of minutes-level numeric values between those two datetime.

function getMinutesRange(startNum, endNum) {
    // Helper to parse a number in YYYYMMDDhhmm format to a Date object in UTC
    const parseNumberToDate = (num) => {
        const str = num.toString();
        if (str.length !== 12) {
            throw new Error("Input numbers must be in the format YYYYMMDDhhmm (12 digits).");
        }
        const year = parseInt(str.slice(0, 4), 10);
        const month = parseInt(str.slice(4, 6), 10) - 1; // Months are 0-indexed in JavaScript
        const day = parseInt(str.slice(6, 8), 10);
        const hours = parseInt(str.slice(8, 10), 10);
        const minutes = parseInt(str.slice(10, 12), 10);

        return new Date(Date.UTC(year, month, day, hours, minutes));
    };

    const start = parseNumberToDate(startNum);
    const end = parseNumberToDate(endNum);

    // Validate the parsed dates
    if (start >= end) {
        throw new Error("The start time must be before the end time.");
    }

    // Helper to format a Date object back to YYYYMMDDhhmm format
    const formatDateToYYYYMMDDhhmm = (date) => {
        const pad = (n) => n.toString().padStart(2, '0');
        const year = date.getUTCFullYear();
        const month = pad(date.getUTCMonth() + 1); // Months are 0-indexed
        const day = pad(date.getUTCDate());
        const hours = pad(date.getUTCHours());
        const minutes = pad(date.getUTCMinutes());
        return `${year}${month}${day}${hours}${minutes}`;
    };

    const results = [];
    let current = new Date(start); // Create a copy to avoid mutating the original date

    while (current < end) { // Change condition to exclude the last minute
        results.push(parseInt(formatDateToYYYYMMDDhhmm(current), 10)); // Push as number
        current.setUTCMinutes(current.getUTCMinutes() + 1); // Increment by one UTC minute
    }

    return results.join(", ");
}

return getMinutesRange(p1, p2)

Join the minutes of same-day tasks together.

Split them into an array.

Get unique elements from that array.

Count the elements in that array.

Bonus points: Convert it back to duration by having it as seconds first, then use the format duration column.

4 Likes

My sample data would return 03:00 for Nov 23, and 09:00 for Nov 24.

1 Like

@ThinhDinh Simply beautiful :clap:

1 Like

Just a further note, I use 2 math columns there because passing the datetime column straight to JavaScript renders it as UTC, not the original time.

1 Like

Thanks a lot for your feedback. So you created this in a second table right? So that means I have the task table with all tasks inside and a second table with all days inside - so for example 365 a year - and there i can then see the overlapping time per day? Or how does it work? I also have to do that for multiple users and so on. I thought the best idea would be to check on all tasks in the table if there is an overlapping time and if yes then it will be less countet time on the overlapping tasks. So for example beside the start and end date I have a tracked time that says 2 hours… if I see that the user has 3 hours to much / overlapping time during the day I remove on for example 2 Tasks which are on that day 1,5 hours each. So that the overlap can be part of the “tracking” but will not be counted. Thanks for your thoughts. Andi

No, it’s all in the same table.

ok. But which kind of result do you get? The amount of ours which overlaps right? Cause I would need that per user and per day etc.

The amount of hours that would be counted for each day, not the amount that overlaps.


In my table it looks like this. So every row has the same result. (Its created based on your input)

Can you see what I am doing wrong?
Thanks, Andi

I think you have to adjust this part. How are you configuring it?

I think taking a couple steps back might allow you to achieve the result you’re looking for. @ThinhDinh can probably confirm if this is the right way to go about it or not:

So I think we can scrap everything but the Query for the same day tasks.

Then create 2 Lookup columns to lookup the StartTime and EndTime for each of the Queried tasks.

Then create 2 more List columns to make a list of all the StartTimes and EndTimes.

Last step is to have ChatGPT help create a JavaScript formula. Sample prompt:

“Create a JavaScript formula to return the number of minutes worked, iterating through each p1 and p2 value 1 at a time, and not counting overlapping time.
For example, p1 is a list of start times like ‘1230, 1500, 1700’ and p2 is a list of end times like ‘1300, 1900, 2200’ where the starttime of 1230 (12:30pm) correlates to an endtime of 1300 (1:00pm). It should count the total minutes worked, iterating through each p1 and p2 value and not counting duplicated”

This should get you the result you want. Make sure to format the starttime and endtime values so the JavaScript column can correctly count the minutes. Not sure if the format I suggested will work. I’m all CSS baby.

I think you did most steps correctly.

At this point though, you should reference the same day query > Display Minutes Task so they have the context of the query, instead of everything (which is why you see the same thing on every row).

Hey, thanks a lot! Now I see a different time in every table. But do you still have an idea, how I can now count the hours per USER… so that I see who has which amount of overlapping time on which day? Or how do you have in mind how I can now work with this value to avoid this overlappings. (I use the tasks for user based time trackings… so I have to break it down per user at the end)

So you want the non-overlapping time or overlapping time?

To have it by user, I assume you have a column for the user ID somewhere in that table. Add it to your “Same Day Query” and you should be good to go.