0

I'm doing an appointment finder which looks through people's calendars and searches for available time for meetings. It works very fine. However, I wanted to exclude the lookup for the break times, which are a DateRange between two DateTimes which both have 1/1/1 as the year (as placeholder) and include the time behind it. I'm iterating through each minute of a working day and a function should determine whether the current time is in the break hours DateRange.

I have this List with a custom DateRange class:

private static List<DateRange> _breakTimes = new List<DateRange>() {
        new DateRange(new DateTime(1, 1, 1, 10, 0, 0), new DateTime(1, 1, 1, 10, 30, 0)),
        new DateRange(new DateTime(1, 1, 1, 13, 30, 0), new DateTime(1, 1, 1, 14, 0, 0))
};

And here's the function that iterates through all working days (I have commented the line where the check function should go):

foreach (var date in GetWorkingDays(startDate, endDate))
        {
            for (int hour = 0; hour <= 24; hour++)
            {
                if (hour < startingHour || hour >= endingHour) continue;

                for (int minute = 0; minute < 60; minute++)
                {
                    var currentDate = new DateTime(date.Year, date.Month, date.Day, hour, minute, 0);

                    bool shouldContinue = false;

                    foreach (var breakTime in _breakTimes)
                    {
                        // Here it should look wheter the current time is in the break times:

                        if ((currentDate.Hour >= breakTime.StartDate.Hour && currentDate.Hour <= breakTime.EndDate.Hour) && (currentDate.Minute > breakTime.StartDate.Minute && currentDate.Minute <= breakTime.EndDate.Minute))
                        {
                            shouldContinue = true;
                            break;
                        }
                    }

                    if (shouldContinue) continue;

                    if (minute == 59)
                    {
                        _workingDaysWithHours.Add(new DateRange(new DateTime(date.Year, date.Month, date.Day, hour, minute, 0), new DateTime(date.Year, date.Month, date.Day, hour + 1, 0, 0)));
                        continue;
                    }

                    _workingDaysWithHours.Add(new DateRange(new DateTime(date.Year, date.Month, date.Day, hour, minute, 0), new DateTime(date.Year, date.Month, date.Day, hour, minute + 1, 0)));
                }
            }
        }

So I only need to know how to check whether the current days' time is between a break time. Hope it's understandable.

Steven2105
  • 540
  • 5
  • 20
  • If you break the breaktimes into minutes as well, you could populate a hashset and check if the date is contained within the hashset – Jason Aug 12 '20 at 12:34
  • Additionally, if you are breaking times into minutes. It's just to call IntersectWith on two sets and you'll know if they overlap. – Jason Aug 12 '20 at 12:38
  • @Jason I don't wanna add every Minute to a List that's why I used a DateRange with DateTimes. Or did you mean something else? – Steven2105 Aug 12 '20 at 12:38
  • What I was suggesting was to flatten the break times into a hashset of minutes with linqs SelectMany, yes you use some memory like with lists, but your lookup time when checking if each minute intercects will be constant not linear. – Jason Aug 12 '20 at 12:44
  • Could you provide some code or example, please? I never used a HashSet or extended Linq. – Steven2105 Aug 12 '20 at 12:46
  • If you want to save memory you could build some sort of tree, where you index by year, day, hour, minute. Where you do a scan anywhere down that heirachy that feels right. – Jason Aug 12 '20 at 12:46
  • Well, I don't care much about the memory consumption, because the program won't get any bigger than this later. I just want to get it working and then maybe, I optimize the code. So I'm only looking for a function which can loop through each minute between the break times and check if the time is between them. – Steven2105 Aug 12 '20 at 12:52
  • Does this answer your question? [Algorithm to detect overlapping periods](https://stackoverflow.com/questions/13513932/algorithm-to-detect-overlapping-periods) – Jason Aug 12 '20 at 13:00
  • @Jason No, unfortunately not. I need a function that can see whether the given time's hours and minutes are in the break hours list with their hours and minutes. – Steven2105 Aug 12 '20 at 13:17

2 Answers2

1

You can modify the code within this example to get what you want Algorithm to detect overlapping periods

foreach (var date in new [] { DateTime.Now })
{
    for (int hour = 0; hour <= 24; hour++)
    {
        if (hour < startingHour || hour >= endingHour) continue;

        for (int minute = 0; minute < 60; minute++)
        {
            var currentDate = new DateTime(date.Year, date.Month, date.Day, hour, minute, 0);

            bool shouldContinue = false;

            var currentTime = new DateTime(1, 1, 1, hour, minute, 0);

            foreach (var breakTime in _breakTimes)
            {

                var isInBreak = breakTime.StartDate <= currentTime && currentTime < breakTime.EndDate;

                if (isInBreak)
                {
                    shouldContinue = true;
                    break;
                }
            }

            if (shouldContinue) continue;

            if (minute == 59)
            {
                _workingDaysWithHours.Add(new DateRange(new DateTime(date.Year, date.Month, date.Day, hour, minute, 0), new DateTime(date.Year, date.Month, date.Day, hour + 1, 0, 0)));
                continue;
            }

            _workingDaysWithHours.Add(new DateRange(new DateTime(date.Year, date.Month, date.Day, hour, minute, 0), new DateTime(date.Year, date.Month, date.Day, hour, minute + 1, 0)));
        }
    }
}
Jason
  • 1,505
  • 5
  • 9
  • Thank you :) Do you think that your solution is better than mine or should I keep it the way I did it? – Steven2105 Aug 12 '20 at 13:42
  • I'd say this answer is probably the most readable. TimeSpan is a class used to represent a time period, not a time within the day. And I would have made a custom class or a named tuple to avoid having to use Item1 etc. But you could modify your answer into a class that takes a datetime and a timespan as an alternative to two datetimes and have it just as readable. – Jason Aug 12 '20 at 13:55
  • Okay. I can make a custom class, because named Tuples aren't supported in the C# version I'm using. Thanks again for you help :) – Steven2105 Aug 12 '20 at 14:00
0

I solved it by using a List with Tuples and add the minutes seperatly:

private static List<Tuple<TimeSpan, int>> _breakTimes = new List<Tuple<TimeSpan, int>>()
        {
            new Tuple<TimeSpan, int>(new TimeSpan(10, 0, 0), 30),
            new Tuple<TimeSpan, int>(new TimeSpan(13, 30, 0), 30)
        };

And this is the function looking whether it's a break time:

foreach (var breakTime in _breakTimes)
                        {
                            if (currentTime >= breakTime.Item1 && currentTime < breakTime.Item1.Add(new TimeSpan(0, breakTime.Item2, 0)))
                            {
                                shouldContinue = true;
                                break;
                            }
                        }
Steven2105
  • 540
  • 5
  • 20