-1

I have a list of objects for each day of week, that store working and not working hours for each day of week.

public class Schedule
{
    public bool IsOn { get; set; }
    public DayOfWeek DayOfWeek { get; set; }
    public short TimeFrom { get; set; } // store time as amount of minutes since start of day
    public short TimeTo { get; set; } // store time as amount of minutes since start of day
}

So what I'm trying to get is time range for each day of week. For example we have 2 items for Monday

new Schedule() { IsOn = true, DayOfWeek = DayOfWeek.Moday, TimeFrom = 540, TimeTo = 1080 }
new Schedule() { IsOn = false, DayOfWeek = DayOfWeek.Moday, TimeFrom = 780, TimeTo = 840 }

I need to show this on UI as: Monday: 9:00-13:00; 14:00-18:00

UPDATE

Main thing I want to know is algorithm on how to solve such thing. If you look at example Monday: 9:00-13:00; 14:00-18:00 you will see that I want to show only working hours. I think that it is something like TimeRange, but I don't know how to code this.

UPDATE 2

To be more clear I will provide an example. User can enter working hours of procedure like a period, e.g. 9:00-12:00 Also user can enter non working hours of procedure like a period, e.g 10:00-11:00. For one day of week it is possible to enter as many time periods (working or non working) as user wants. Adding and storing this to database is not a problem.

Problem is to show time periods for user during preview.

So for example user entered:

  1. 9:00-12:00 working hours
  2. 10:00-11:00 non working hours
  3. 14:00-17:00 working hours
  4. 15:00-15:30 non working hours

I need to show all these like:

9:00-10:00; 11:00-12:00; 14:00-15:00; 15:30-17:00;

UPDATE 3

I think this may be related to graphs. Please help on selecting algorithm.

Vladimir Rodchenko
  • 1,052
  • 15
  • 25
  • Why not use built-in DateTime for `TimeFrom` and `TimeTo`? – 001 Oct 11 '15 at 16:55
  • 2
    @JohnnyMopp because `DateTime` represents a specific point in time, not a time of day. However `TimeSpan` might be a slightly better choice. – juharr Oct 11 '15 at 17:25

2 Answers2

3

The following should give you the output you want. Using the sample data you gave this is the result.

Output

Monday: 09:00-18:00; 13:00-14:00

Code

void Main()
{
    var schedules = new[]{
        new Schedule() { IsOn = true, DayOfWeek = DayOfWeek.Monday, TimeFrom = 540, TimeTo = 1080 },
        new Schedule() { IsOn = false, DayOfWeek = DayOfWeek.Monday, TimeFrom = 780, TimeTo = 840 }
    };


    var byDay = schedules.GroupBy(i => i.DayOfWeek)
                .Select(i =>
                {
                    var times = i.Select(t => string.Format(@"{0:hh\:mm}-{1:hh\:mm}", TimeSpan.FromMinutes(t.TimeFrom), TimeSpan.FromMinutes(t.TimeTo)));
                    return string.Format("{0}: {1}", i.Key, string.Join("; ", times));
                });

    foreach (var day in byDay)
    {
        Console.WriteLine(byDay);
    }
}

public class Schedule
{
    public bool IsOn { get; set; }
    public DayOfWeek DayOfWeek { get; set; }
    public short TimeFrom { get; set; } // store time as amount of minutes since start of day
    public short TimeTo { get; set; } // store time as amount of minutes since start of day
}
Tedford
  • 2,842
  • 2
  • 35
  • 45
  • this is good code, but it is not solving my problem. I need to show only working hours, while your example shows times. – Vladimir Rodchenko Oct 12 '15 at 14:35
  • 1
    @VladimirRodchenko Can you refine your question then as it is difficult to understand what you are asking. There is no universally constant "working hours"; if that is not what is indicated by schedule then there is no way to calculate what you really want. – Tedford Oct 12 '15 at 15:18
  • I updated my question, hope this will help. Thank you for trying to help me. – Vladimir Rodchenko Oct 12 '15 at 19:43
0

Finally, I found solution.

    public static IEnumerable<Tuple<short, short>> ExcludeIntervals(IEnumerable<ISchedule> range)
    {
        var list = range
            .SelectMany(x => new[] {Tuple.Create(x.TimeFrom, x.IsOn), Tuple.Create(x.TimeTo, !x.IsOn)})
            .OrderBy(d => d.Item1).ThenBy(d => d.Item2)
            .ToList();

        var first = default(short);
        var count = 1;

        foreach (var item in list)
        {
            if (item.Item2) // false - start of unavailability interval. true - end of unavailability interval.
            {
                if (--count == 0) // Become available.
                {
                    first = item.Item1;
                }
            }
            else
            {
                if (++count == 1)
                {
                    var last = item.Item1;
                    if (last >= first) // if next unavailability starts right after previous ended, then no gap.
                    {
                        yield return Tuple.Create(first, last);
                    }
                }
            }
        }
    }

    public interface ISchedule
    {
        bool IsOn { get; set; }
        short TimeFrom { get; set; }
        short TimeTo { get; set; }
    }
Vladimir Rodchenko
  • 1,052
  • 15
  • 25