using System.Collections.Generic;
using System.Diagnostics;
public static void Main( string[] args )
var periods = new List<Period> {
new Period( "Period 1", Days.Workdays, TimeSpan.FromHours(0), TimeSpan.FromHours(7) ),
new Period( "Period 2", Days.Workdays, TimeSpan.FromHours(7), TimeSpan.FromHours(20) ),
new Period( "Period 3", Days.Workdays, TimeSpan.FromHours(20), TimeSpan.FromHours(22) ),
new Period( "Period 4", Days.Workdays, TimeSpan.FromHours(22), TimeSpan.FromHours(07) ),
new Period( "Period 5", Days.Weekend, TimeSpan.FromHours(0), TimeSpan.FromHours(7) ),
new Period( "Period 6", Days.Weekend, TimeSpan.FromHours(7), TimeSpan.FromHours(22) ),
new Period( "Period 7", Days.Weekend, TimeSpan.FromHours(22), TimeSpan.FromHours(24) ),
new Period( "Period 8", Days.Holiday, TimeSpan.FromHours(0), TimeSpan.FromHours(24) ),
var holidays = new List<DateTime> {
new DateTime( 2017, 1, 1 ),
new DateTime( 2017, 1, 3 ),
new DateTime( 2017, 1, 6 ),
var sc = new ShiftCalculator( periods, holidays );
var shiftperiods = sc.GetShiftPeriods( new DateTime( 2016, 12, 31, 22, 00, 00 ), new DateTime( 2017, 01, 07, 08, 00, 00 ) ).ToList();
foreach ( var sp in shiftperiods )
Console.WriteLine( "{0} - {1} - {2} - {3:00.00}h", sp.Period.Name, sp.Period.Days, sp.Start, sp.Duration.TotalHours );
Workdays = Monday | Tuesday | Wednesday | Thursday | Friday,
Weekend = Saturday | Sunday,
[DebuggerDisplay("{Name}: {Days} ({Start}-{End})")]
public Period( string name, Days days, TimeSpan start, TimeSpan end )
if ( days.HasFlag( Days.Holiday ) && days != Days.Holiday )
throw new ArgumentException( "days" );
public string Name { get; private set; }
public Days Days { get; private set; }
public TimeSpan Start { get; private set; }
public TimeSpan End { get; private set; }
public Period Period { get; set; }
public DateTime Start { get; set; }
public TimeSpan Duration { get; set; }
private readonly List<Period> _periods;
private readonly List<DateTime> _holidays;
public ShiftCalculator( IEnumerable<Period> periods, IEnumerable<DateTime> holidays )
_periods = periods.ToList();
_holidays = holidays.Select( e => e.Date ).ToList();
public IEnumerable<ShiftPeriod> GetShiftPeriods( DateTime start, DateTime end )
if ( start > end ) throw new ArgumentException( "end" );
var period = GetPeriodByDateTime( current );
var next = current.Date + period.End;
yield return new ShiftPeriod
Duration = next - current,
private Days GetDayFromDateTime( DateTime datetime )
if ( _holidays.Contains( datetime.Date ) )
switch ( datetime.DayOfWeek )
case DayOfWeek.Wednesday:
throw new InvalidOperationException();
private Period GetPeriodByDateTime( DateTime datetime )
var day = GetDayFromDateTime( datetime );
var timeOfDay = datetime.TimeOfDay;
var period = _periods.Where(e => e.Days.HasFlag(day) && e.Start <= e.End? (e.Start <= timeOfDay && e.End > timeOfDay) : (e.Start <= timeOfDay || e.End > timeOfDay))
throw new InvalidOperationException();