0
votes

As a part of my employees project, I have a schedule routine for the crews/shifts of work. I wonder what is the best way to examine today state (work or day off) if I'm working over a non fixed pattern of work days like so: let's say start date of roaster is 1 Jan 2018 and the pattern is: first day is morning shift (1 Jan: from 6 am to 14 pm) then second day is afternoon shift (2 Jan: from 14 pm to 10 pm) then third day is night overlap shift (3 Jan: 10 pm to 4 Jan 10 am) then forth and fifth days (4 Jan and 5 Jan) are days off, and after that it all start over again form 6 Jan as a morning shift and so on. So as you see it's not related to days of week (as usual) so my variables is the start date and the pattern. What is the best approach to do it?

3
How about computing (the number of days between query date and start date) mod the pattern length, and that gives you the sub day of the pattern? - NetMage
I'd write it on a whiteboard, stare at it for a few hours and try to see the pattern for myself. - Milster
@NetMage that's already what I'm confused about, i already know that pattern as I explained in my question but what I want to achieve is how I will calculate it over dates and not over days of week basis. - Sherif Riad
@Milster again, I already know the pattern. But how - for an example - I know that today (25 Jun) is work or day off if the schedule start date is (1 Jan) over the pattern I mentioned in my question? - Sherif Riad
It's the 176th day of the year. (177 in a leap year). 176 mod 5 equals 1. So it's the second day of work (0 based index), an afternoon shift. Does that help you to get an idea? - Milster

3 Answers

2
votes

Here is a sample function that calculates the state for a date:

void Main() {
    var workPattern = new List<DayState> { DayState.MorningShift, DayState.AfternoonShift, DayState.NightShift, DayState.OffDay, DayState.OffDay };
    var startDate = new DateTime(2018, 1, 1);

    var queryDate = new DateTime(2018, 1, 4);
    Console.WriteLine($"{queryDate:d} is {StateOfDate(startDate, workPattern, queryDate)}");

    queryDate = new DateTime(2018, 1, 21);
    Console.WriteLine($"{queryDate:d} is {StateOfDate(startDate, workPattern, queryDate)}");

    queryDate = new DateTime(2018, 2, 6);
    Console.WriteLine($"{queryDate:d} is {StateOfDate(startDate, workPattern, queryDate)}");

    queryDate = new DateTime(2018, 3, 4);
    Console.WriteLine($"{queryDate:d} is {StateOfDate(startDate, workPattern, queryDate)}");
}

// Define other methods and classes here
public enum DayState {
    MorningShift, AfternoonShift, NightShift, OffDay
};

public DayState StateOfDate(DateTime startDate, List<DayState> workPattern, DateTime queryDate) {
    var numDays = Math.Floor((queryDate-startDate).TotalDays);
    var patternOffset = ((int)numDays) % workPattern.Count;
    return workPattern[patternOffset];
}
1
votes

Just for completion I'd like to provide the following class based approach:

public class Program
{
    static void Main(string[] args)
    {
        var shiftScheduler = new ShiftScheduler(new DateTime(2018, 01, 01));
        var requestedShift = shiftScheduler.GetShift(new DateTime(2018, 01, 05));

        Console.WriteLine(requestedShift.IsWorkDay
          ? $"Scheduled from ${requestedShift.HoursBegin}{requestedShift.MinutesBegin:00} " +
            $"to {requestedShift.HoursEnd}{requestedShift.MinutesEnd:00}"
          : "No work today");
    }

}

public class Shift
{
    public Shift(int hoursBegin, int hoursEnd, int minutesBegin, int minutesEnd, bool isWorkDay)
    {
        HoursBegin = hoursBegin;
        HoursEnd = hoursEnd;
        MinutesBegin = minutesBegin;
        MinutesEnd = minutesEnd;
        IsWorkDay = isWorkDay;
    }

    public int HoursBegin { get; set; }
    public int HoursEnd { get; set; }
    public int MinutesBegin { get; set; }
    public int MinutesEnd { get; set; }
    public bool IsWorkDay { get; set; }
}

public class ShiftScheduler
{
    private readonly Dictionary<int, Shift> _shifts = new Dictionary<int, Shift>();
    private readonly DateTime _startDate;

    public ShiftScheduler(DateTime startDate)
    {
        Initialize();
        _startDate = startDate;
    }

    private void Initialize()
    {
        _shifts.Add(0, new Shift(6, 14, 0, 0, true)); // Day 1
        _shifts.Add(1, new Shift(14, 22, 0, 0, true)); // Day 2
        _shifts.Add(2, new Shift(22, 6, 0, 0, true)); // Day 3
        _shifts.Add(3, new Shift(0, 0, 0, 0, false)); // Day 4, day off
        _shifts.Add(4, new Shift(0, 0, 0, 0, false)); // Day 5, day off
    }

    public Shift GetShift(DateTime targetDate)
    {
        int days = (int)Math.Floor((targetDate - _startDate).TotalDays);
        if (days < 0)
        {
            throw new ArgumentException("Target date prior to start date.");
        }

        Shift targetShift;
        _shifts.TryGetValue(days % _shifts.Count, out targetShift);
        return targetShift;
    }
}
0
votes

How About This : Ps : if u don't like setting the IsOff flag from the constructor you should set it as a set Method of the Date property

public Class WorkDay
{
    public DateTime Date { get; set; }
    public ShiftType ShiftType { get; set; }
    public bool IsOff { get; set;}
    public string HolidayName { get; set; }

    public WorkDay(DateTime date)
    {
          Date = date;
          if (date.DayOfWeek = DayOfWeek.Saturday || date.DayOfWeek = DayOfWeek.Sunday )
          IsOff = true;
    } 
}



enum ShiftType 
{
   Morning, Mid , Night
}