public void GetGapTest() { DateTime now = ClockProxy.Clock.Now; SchoolDay schoolDay = new SchoolDay( now ); TimePeriodCollection excludePeriods = new TimePeriodCollection(); TimeGapCalculator<TimeRange> gapCalculator = new TimeGapCalculator<TimeRange>(); excludePeriods.AddAll( schoolDay ); Assert.AreEqual( gapCalculator.GetGaps( excludePeriods ).Count, 0 ); Assert.AreEqual( gapCalculator.GetGaps( excludePeriods, schoolDay ).Count, 0 ); excludePeriods.Clear(); excludePeriods.Add( schoolDay.Lesson1 ); excludePeriods.Add( schoolDay.Lesson2 ); excludePeriods.Add( schoolDay.Lesson3 ); excludePeriods.Add( schoolDay.Lesson4 ); ITimePeriodCollection gaps2 = gapCalculator.GetGaps( excludePeriods ); Assert.AreEqual( gaps2.Count, 3 ); Assert.IsTrue( gaps2[ 0 ].IsSamePeriod( schoolDay.Break1 ) ); Assert.IsTrue( gaps2[ 1 ].IsSamePeriod( schoolDay.Break2 ) ); Assert.IsTrue( gaps2[ 2 ].IsSamePeriod( schoolDay.Break3 ) ); TimeRange testRange3 = new TimeRange( schoolDay.Lesson1.Start, schoolDay.Lesson4.End ); ITimePeriodCollection gaps3 = gapCalculator.GetGaps( excludePeriods, testRange3 ); Assert.AreEqual( gaps3.Count, 3 ); Assert.IsTrue( gaps3[ 0 ].IsSamePeriod( schoolDay.Break1 ) ); Assert.IsTrue( gaps3[ 1 ].IsSamePeriod( schoolDay.Break2 ) ); Assert.IsTrue( gaps3[ 2 ].IsSamePeriod( schoolDay.Break3 ) ); TimeRange testRange4 = new TimeRange( schoolDay.Start.AddHours( -1 ), schoolDay.End.AddHours( 1 ) ); ITimePeriodCollection gaps4 = gapCalculator.GetGaps( excludePeriods, testRange4 ); Assert.AreEqual( gaps4.Count, 5 ); Assert.IsTrue( gaps4[ 0 ].IsSamePeriod( new TimeRange( testRange4.Start, schoolDay.Start ) ) ); Assert.IsTrue( gaps4[ 1 ].IsSamePeriod( schoolDay.Break1 ) ); Assert.IsTrue( gaps4[ 2 ].IsSamePeriod( schoolDay.Break2 ) ); Assert.IsTrue( gaps4[ 3 ].IsSamePeriod( schoolDay.Break3 ) ); Assert.IsTrue( gaps4[ 4 ].IsSamePeriod( new TimeRange( testRange4.End, testRange3.End ) ) ); excludePeriods.Clear(); excludePeriods.Add( schoolDay.Lesson1 ); ITimePeriodCollection gaps8 = gapCalculator.GetGaps( excludePeriods, schoolDay.Lesson1 ); Assert.AreEqual( gaps8.Count, 0 ); TimeRange testRange9 = new TimeRange( schoolDay.Lesson1.Start.Subtract( new TimeSpan( 1 ) ), schoolDay.Lesson1.End.Add( new TimeSpan( 1 ) ) ); ITimePeriodCollection gaps9 = gapCalculator.GetGaps( excludePeriods, testRange9 ); Assert.AreEqual( gaps9.Count, 2 ); Assert.AreEqual( gaps9[ 0 ].Duration, new TimeSpan( 1 ) ); Assert.AreEqual( gaps9[ 1 ].Duration, new TimeSpan( 1 ) ); }
// ---------------------------------------------------------------------- public IList <MyTimePeriod> GetGaps(IEnumerable <MyTimePeriod> periods) { TimeGapCalculator <TimeRange> gapCalculator = new TimeGapCalculator <TimeRange>(); TimePeriodCollection calcPeriods = new TimePeriodCollection(); foreach (MyTimePeriod period in periods) { calcPeriods.Add(new TimeRange(period.Start, period.End)); } List <MyTimePeriod> gaps = new List <MyTimePeriod>(); if (calcPeriods.Count == 0) { return(gaps); } ITimePeriodCollection calcCaps = gapCalculator.GetGaps(calcPeriods); foreach (TimeRange calcCap in calcCaps) { gaps.Add(new MyTimePeriod { Start = calcCap.Start, End = calcCap.End }); } return(gaps); } // GetGaps
public void CalendarGetGapTest() { // simmulation of some reservations TimePeriodCollection periods = new TimePeriodCollection(); periods.Add( new Days( 2011, 3, 7, 2 ) ); periods.Add( new Days( 2011, 3, 16, 2 ) ); // the overall search range CalendarTimeRange limits = new CalendarTimeRange( new DateTime( 2011, 3, 4 ), new DateTime( 2011, 3, 21 ) ); Days days = new Days( limits.Start, limits.Duration.Days + 1 ); ITimePeriodCollection dayList = days.GetDays(); foreach ( Day day in dayList ) { if ( !limits.HasInside( day ) ) { continue; // outside of the search scope } if ( day.DayOfWeek == DayOfWeek.Saturday || day.DayOfWeek == DayOfWeek.Sunday ) { periods.Add( day ); // // exclude weekend day } } TimeGapCalculator<TimeRange> gapCalculator = new TimeGapCalculator<TimeRange>( new TimeCalendar() ); ITimePeriodCollection gaps = gapCalculator.GetGaps( periods, limits ); Assert.AreEqual( gaps.Count, 4 ); Assert.IsTrue( gaps[ 0 ].IsSamePeriod( new TimeRange( new DateTime( 2011, 3, 4 ), Duration.Days( 1 ) ) ) ); Assert.IsTrue( gaps[ 1 ].IsSamePeriod( new TimeRange( new DateTime( 2011, 3, 9 ), Duration.Days( 3 ) ) ) ); Assert.IsTrue( gaps[ 2 ].IsSamePeriod( new TimeRange( new DateTime( 2011, 3, 14 ), Duration.Days( 2 ) ) ) ); Assert.IsTrue( gaps[ 3 ].IsSamePeriod( new TimeRange( new DateTime( 2011, 3, 18 ), Duration.Days( 1 ) ) ) ); }
public void CalendarGetGapTest() { // simmulation of some reservations TimePeriodCollection periods = new TimePeriodCollection(); periods.Add(new Days(2011, 3, 7, 2)); periods.Add(new Days(2011, 3, 16, 2)); // the overall search range CalendarTimeRange limits = new CalendarTimeRange(new DateTime(2011, 3, 4), new DateTime(2011, 3, 21)); Days days = new Days(limits.Start, limits.Duration.Days + 1); ITimePeriodCollection dayList = days.GetDays(); foreach (Day day in dayList) { if (!limits.HasInside(day)) { continue; // outside of the search scope } if (day.DayOfWeek == DayOfWeek.Saturday || day.DayOfWeek == DayOfWeek.Sunday) { periods.Add(day); // // exclude weekend day } } TimeGapCalculator <TimeRange> gapCalculator = new TimeGapCalculator <TimeRange>(new TimeCalendar()); ITimePeriodCollection gaps = gapCalculator.GetGaps(periods, limits); Assert.Equal(4, gaps.Count); Assert.True(gaps[0].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 4), Duration.Days(1)))); Assert.True(gaps[1].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 9), Duration.Days(3)))); Assert.True(gaps[2].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 14), Duration.Days(2)))); Assert.True(gaps[3].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 18), Duration.Days(1)))); } // CalendarGetGapTest
/// <summary> /// <paramref name="current"/> 기준으로 예외 기간 등을 고려한 후행의 가장 근접한 WeekRange를 구합니다. /// </summary> /// <param name="current"></param> /// <returns></returns> private WeekRange FindNextWeek(WeekRange current) { if (IsDebugEnabled) { log.Debug("현 Week [{0}]의 다음 Week 기간을 구합니다...", current); } WeekRange result; if (ExcludePeriods.Count == 0) { result = current.GetNextWeek(); } else { var limits = new TimeRange(current.End.AddTicks(1), DateTime.MaxValue); var gapCalculator = new TimeGapCalculator <TimeRange>(TimeCalendar); var remainingPeriods = gapCalculator.GetGaps(ExcludePeriods, limits); result = (remainingPeriods.Count > 0) ? new WeekRange(remainingPeriods[0].Start, TimeCalendar) : null; } if (IsDebugEnabled) { log.Debug("현 Week의 다음 Week 기간을 구했습니다. current=[{0}], next=[{1}]", current, result); } return(result); }
/// <summary> /// <paramref name="current"/> 기준으로 예외기간 등을 고려한 선행의 WeekRange를 구합니다. /// </summary> /// <param name="current"></param> /// <returns></returns> private WeekRange FindPreviousWeek(WeekRange current) { if (IsDebugEnabled) { log.Debug("현 Week [{0}]의 이전 Week 기간을 구합니다...", current); } WeekRange result; if (ExcludePeriods.Count == 0) { result = current.GetPreviousWeek(); } else { var limits = new TimeRange(DateTime.MinValue, current.Start.AddTicks(-1)); var gapCalculator = new TimeGapCalculator <TimeRange>(TimeCalendar); var remainingPeriods = gapCalculator.GetGaps(ExcludePeriods, limits); result = (remainingPeriods.Count > 0) ? new WeekRange(remainingPeriods[remainingPeriods.Count - 1].End, TimeCalendar) : null; } if (IsDebugEnabled) { log.Debug("현 Week의 이전 Week 기간을 구했습니다. current=[{0}], next=[{1}]", current, result); } return(result); }
} // GapCalculator8 // ---------------------------------------------------------------------- public void GapCalculator16(int count) { TimeRange limits = new TimeRange(new DateTime(2011, 3, 29), new DateTime(2011, 6, 1)); TimeGapCalculator <TimeRange> gapCalculator = new TimeGapCalculator <TimeRange>(); TimePeriodCollection excludePeriods = new TimePeriodCollection(); for (int i = 0; i < 2; i++) { excludePeriods.Add(new TimeRange(new DateTime(2011, 3, 30, 00, 00, 0), new DateTime(2011, 3, 31, 00, 00, 0))); excludePeriods.Add(new TimeRange(new DateTime(2011, 3, 30, 00, 00, 0), new DateTime(2011, 3, 31, 00, 00, 0))); excludePeriods.Add(new TimeRange(new DateTime(2011, 4, 01, 00, 00, 0), new DateTime(2011, 4, 12, 00, 00, 0))); excludePeriods.Add(new TimeRange(new DateTime(2011, 4, 12, 00, 00, 0), new DateTime(2011, 4, 18, 00, 00, 0))); excludePeriods.Add(new TimeRange(new DateTime(2011, 4, 29, 00, 00, 0), new DateTime(2011, 4, 30, 00, 00, 0))); excludePeriods.Add(new TimeRange(new DateTime(2011, 4, 29, 00, 00, 0), new DateTime(2011, 4, 30, 00, 00, 0))); excludePeriods.Add(new TimeRange(new DateTime(2011, 5, 01, 00, 00, 0), new DateTime(2011, 5, 12, 00, 00, 0))); excludePeriods.Add(new TimeRange(new DateTime(2011, 5, 12, 00, 00, 0), new DateTime(2011, 5, 18, 00, 00, 0))); } Console.Write("GapCalculator 16 ({0:#,0}): ", count); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); for (int i = 0; i < count; i++) { gapCalculator.GetGaps(excludePeriods, limits); } stopwatch.Stop(); Console.WriteLine(" {0} ms", stopwatch.ElapsedMilliseconds); } // GapCalculator16
public void NoPeriodsTest() { var limits = new TimeRange(new DateTime(2011, 3, 1), new DateTime(2011, 3, 5)); var gapCalculator = new TimeGapCalculator<TimeRange>(); var gaps = gapCalculator.GetGaps(new TimePeriodCollection(), limits); gaps.Count.Should().Be(1); gaps[0].IsSamePeriod(limits).Should().Be.True(); }
public void NoPeriodsTest() { TimeRange limits = new TimeRange(new DateTime(2011, 3, 1), new DateTime(2011, 3, 5)); TimeGapCalculator <TimeRange> gapCalculator = new TimeGapCalculator <TimeRange>(); ITimePeriodCollection gaps = gapCalculator.GetGaps(new TimePeriodCollection(), limits); Assert.Equal(1, gaps.Count); Assert.True(gaps[0].IsSamePeriod(limits)); } // NoPeriodsTest
public void PeriodEqualsLimitsTest() { var limits = new TimeRange(new DateTime(2011, 3, 1), new DateTime(2011, 3, 5)); var gapCalculator = new TimeGapCalculator<TimeRange>(); var excludePeriods = new TimePeriodCollection { limits }; var gaps = gapCalculator.GetGaps(excludePeriods, limits); gaps.Count.Should().Be(0); }
public void GetGapTest() { DateTime now = ClockProxy.Clock.Now; SchoolDay schoolDay = new SchoolDay(now); TimePeriodCollection excludePeriods = new TimePeriodCollection(); TimeGapCalculator <TimeRange> gapCalculator = new TimeGapCalculator <TimeRange>(); excludePeriods.AddAll(schoolDay); Assert.Equal(0, gapCalculator.GetGaps(excludePeriods).Count); Assert.Equal(0, gapCalculator.GetGaps(excludePeriods, schoolDay).Count); excludePeriods.Clear(); excludePeriods.Add(schoolDay.Lesson1); excludePeriods.Add(schoolDay.Lesson2); excludePeriods.Add(schoolDay.Lesson3); excludePeriods.Add(schoolDay.Lesson4); ITimePeriodCollection gaps2 = gapCalculator.GetGaps(excludePeriods); Assert.Equal(3, gaps2.Count); Assert.True(gaps2[0].IsSamePeriod(schoolDay.Break1)); Assert.True(gaps2[1].IsSamePeriod(schoolDay.Break2)); Assert.True(gaps2[2].IsSamePeriod(schoolDay.Break3)); TimeRange testRange3 = new TimeRange(schoolDay.Lesson1.Start, schoolDay.Lesson4.End); ITimePeriodCollection gaps3 = gapCalculator.GetGaps(excludePeriods, testRange3); Assert.Equal(3, gaps3.Count); Assert.True(gaps3[0].IsSamePeriod(schoolDay.Break1)); Assert.True(gaps3[1].IsSamePeriod(schoolDay.Break2)); Assert.True(gaps3[2].IsSamePeriod(schoolDay.Break3)); TimeRange testRange4 = new TimeRange(schoolDay.Start.AddHours(-1), schoolDay.End.AddHours(1)); ITimePeriodCollection gaps4 = gapCalculator.GetGaps(excludePeriods, testRange4); Assert.Equal(5, gaps4.Count); Assert.True(gaps4[0].IsSamePeriod(new TimeRange(testRange4.Start, schoolDay.Start))); Assert.True(gaps4[1].IsSamePeriod(schoolDay.Break1)); Assert.True(gaps4[2].IsSamePeriod(schoolDay.Break2)); Assert.True(gaps4[3].IsSamePeriod(schoolDay.Break3)); Assert.True(gaps4[4].IsSamePeriod(new TimeRange(testRange4.End, testRange3.End))); excludePeriods.Clear(); excludePeriods.Add(schoolDay.Lesson1); ITimePeriodCollection gaps8 = gapCalculator.GetGaps(excludePeriods, schoolDay.Lesson1); Assert.Equal(0, gaps8.Count); TimeRange testRange9 = new TimeRange(schoolDay.Lesson1.Start.Subtract(new TimeSpan(1)), schoolDay.Lesson1.End.Add(new TimeSpan(1))); ITimePeriodCollection gaps9 = gapCalculator.GetGaps(excludePeriods, testRange9); Assert.Equal(2, gaps9.Count); Assert.Equal <TimeSpan>(gaps9[0].Duration, new TimeSpan(1)); Assert.Equal <TimeSpan>(gaps9[1].Duration, new TimeSpan(1)); } // GetGapsTest
public void PeriodEqualsLimitsTest() { TimeRange limits = new TimeRange(new DateTime(2011, 3, 1), new DateTime(2011, 3, 5)); TimeGapCalculator <TimeRange> gapCalculator = new TimeGapCalculator <TimeRange>(); TimePeriodCollection excludePeriods = new TimePeriodCollection(); excludePeriods.Add(limits); ITimePeriodCollection gaps = gapCalculator.GetGaps(excludePeriods, limits); Assert.AreEqual(gaps.Count, 0); } // PeriodEqualsLimitsTest
public void PeriodLargerThanLimitsTest() { TimeRange limits = new TimeRange(new DateTime(2011, 3, 1), new DateTime(2011, 3, 5)); TimeGapCalculator <TimeRange> gapCalculator = new TimeGapCalculator <TimeRange>(); TimePeriodCollection excludePeriods = new TimePeriodCollection(); excludePeriods.Add(new TimeRange(new DateTime(2011, 2, 1), new DateTime(2011, 4, 1))); ITimePeriodCollection gaps = gapCalculator.GetGaps(excludePeriods, limits); Assert.Equal(0, gaps.Count); } // PeriodLargerThanLimitsTest
public void MomentPeriodTest() { TimeRange limits = new TimeRange(new DateTime(2011, 3, 1), new DateTime(2011, 3, 20)); TimeGapCalculator <TimeRange> gapCalculator = new TimeGapCalculator <TimeRange>(); TimePeriodCollection excludePeriods = new TimePeriodCollection(); excludePeriods.Add(new TimeRange(new DateTime(2011, 3, 10), new DateTime(2011, 3, 10))); ITimePeriodCollection gaps = gapCalculator.GetGaps(excludePeriods, limits); Assert.Equal(1, gaps.Count); Assert.True(gaps[0].IsSamePeriod(limits)); } // MomentPeriodTest
public void PeriodTouchingLimitsEndTest() { TimeRange limits = new TimeRange(new DateTime(2011, 3, 1), new DateTime(2011, 3, 20)); TimeGapCalculator <TimeRange> gapCalculator = new TimeGapCalculator <TimeRange>(); TimePeriodCollection excludePeriods = new TimePeriodCollection(); excludePeriods.Add(new TimeRange(new DateTime(2011, 3, 10), new DateTime(2011, 3, 20))); ITimePeriodCollection gaps = gapCalculator.GetGaps(excludePeriods, limits); Assert.AreEqual(gaps.Count, 1); Assert.IsTrue(gaps[0].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 1), new DateTime(2011, 3, 10)))); } // PeriodTouchingLimitsEndTest
/// <summary> /// <paramref name="fromTime"/> ~ <paramref name="toTime"/> 기간의 WorkingTime 의 기간을 구합니다. /// </summary> /// <param name="fromTime"></param> /// <param name="toTime"></param> /// <returns></returns> public TimeSpan Difference(DateTime fromTime, DateTime toTime) { if (IsDebugEnabled) { log.Debug("fromTime[{0}] ~ toTime[{1}] 의 WorkingTime 기간을 구합니다.", fromTime, toTime); } if (Equals(fromTime, toTime)) { return(TimeSpan.Zero); } var filterIsEmpty = _collectorFilter.WeekDays.Count == 0 && _collectorFilter.CollectingHours.Count == 0 && _collectorFilter.CollectingDayHours.Count == 0; if (filterIsEmpty) { return (new DateDiff(fromTime, toTime, _calendar.Culture.Calendar, _calendar.FirstDayOfWeek, _calendar.YearBaseMonth) .Difference); } var differenceRange = new TimeRange(fromTime, toTime); var collector = new CalendarPeriodCollector(_collectorFilter, new TimeRange(differenceRange.Start.Date, differenceRange.End.Date.AddDays(1)), SeekDirection.Forward, _calendar); // Gap을 계산합니다. var gapCalculator = new TimeGapCalculator <TimeRange>(_calendar); var gaps = gapCalculator.GetGaps(collector.Periods, differenceRange); var difference = gaps.Aggregate(TimeSpan.Zero, (current, gap) => current.Add(gap.Duration)); if (IsDebugEnabled) { log.Debug("fromTime[{0}] ~ toTime[{1}] 의 WorkingTime 기간은 [{2}] 입니다!!!", fromTime, toTime, difference); } return((fromTime < toTime) ? difference : difference.Negate()); }
public void PeriodOutsideTouchingLimitsTest() { var limits = new MonthRange(2011, 3); // new TimeRange(new DateTime(2011, 3, 1), new DateTime(2011, 3, 31)); var gapCalculator = new TimeGapCalculator<TimeRange>(); var excludePeriods = new TimePeriodCollection { new TimeRange(new DateTime(2011, 2, 1), new DateTime(2011, 3, 5)), new TimeRange(new DateTime(2011, 3, 20), new DateTime(2011, 4, 15)) }; var gaps = gapCalculator.GetGaps(excludePeriods, limits); gaps.Count.Should().Be(1); gaps[0].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 5), new DateTime(2011, 3, 20))).Should().Be.True(); }
public void PeriodOutsideTouchingLimitsTest() { TimeRange limits = new TimeRange(new DateTime(2011, 3, 1), new DateTime(2011, 3, 31)); TimeGapCalculator <TimeRange> gapCalculator = new TimeGapCalculator <TimeRange>(); TimePeriodCollection excludePeriods = new TimePeriodCollection(); excludePeriods.Add(new TimeRange(new DateTime(2011, 2, 1), new DateTime(2011, 3, 5))); excludePeriods.Add(new TimeRange(new DateTime(2011, 3, 20), new DateTime(2011, 4, 15))); ITimePeriodCollection gaps = gapCalculator.GetGaps(excludePeriods, limits); Assert.Equal(1, gaps.Count); Assert.True(gaps[0].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 5), new DateTime(2011, 3, 20)))); } // PeriodOutsideTouchingLimitsTest
public void OverlappingPeriods3Test() { TimeRange limits = new TimeRange(new DateTime(2011, 3, 29), new DateTime(2011, 4, 1)); TimeGapCalculator <TimeRange> gapCalculator = new TimeGapCalculator <TimeRange>(); TimePeriodCollection excludePeriods = new TimePeriodCollection(); excludePeriods.Add(new TimeRange(new DateTime(2011, 3, 30, 00, 00, 0), new DateTime(2011, 3, 31, 00, 00, 0))); excludePeriods.Add(new TimeRange(new DateTime(2011, 3, 30, 00, 00, 0), new DateTime(2011, 3, 31, 00, 00, 0))); ITimePeriodCollection gaps = gapCalculator.GetGaps(excludePeriods, limits); Assert.Equal(2, gaps.Count); Assert.True(gaps[0].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 29), new DateTime(2011, 3, 30)))); Assert.True(gaps[1].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 31), new DateTime(2011, 4, 01)))); } // OverlappingPeriods3Test
public void TouchingPeriodsTest() { TimeRange limits = new TimeRange(new DateTime(2011, 3, 29), new DateTime(2011, 4, 1)); TimeGapCalculator <TimeRange> gapCalculator = new TimeGapCalculator <TimeRange>(); TimePeriodCollection excludePeriods = new TimePeriodCollection(); excludePeriods.Add(new TimeRange(new DateTime(2011, 3, 30, 00, 00, 0), new DateTime(2011, 3, 30, 08, 30, 0))); excludePeriods.Add(new TimeRange(new DateTime(2011, 3, 30, 08, 30, 0), new DateTime(2011, 3, 30, 12, 00, 0))); excludePeriods.Add(new TimeRange(new DateTime(2011, 3, 30, 10, 00, 0), new DateTime(2011, 3, 31, 00, 00, 0))); ITimePeriodCollection gaps = gapCalculator.GetGaps(excludePeriods, limits); Assert.AreEqual(gaps.Count, 2); Assert.IsTrue(gaps[0].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 29), new DateTime(2011, 3, 30)))); Assert.IsTrue(gaps[1].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 31), new DateTime(2011, 4, 01)))); } // TouchingPeriodsTest
public static bool NeedPause(this PlanItem dienst, out int pause) { pause = 0; if (dienst.Zeitraum.Duration.NeedPause()) { pause = 30; return(true); } //wenn keine Pause aber Großteam noch ist if (dienst.HatGrossteam) { var tp = new TimePeriodCollection(new List <ITimePeriod>() { dienst.Zeitraum, dienst.Arbeitstag.Grossteam }); if (tp.HasGaps()) { var gapCalculator = new TimeGapCalculator <TimeRange>(new TimeCalendar()); var gaps = gapCalculator.GetGaps(tp); var gap = (int)Math.Round(gaps.First().Duration.TotalMinutes, MidpointRounding.ToEven); //sollte nur eine geben, sind ja nur 2 Zeiten if (gap < 30) { pause = 30 - gap; return(true); } } else { var periodCombiner = new TimePeriodCombiner <TimeRange>(); var combinedPeriods = periodCombiner.CombinePeriods(tp); if (combinedPeriods.First().Duration.NeedPause()) { pause = 30; return(true); } } } return(false); }
} // TimeGapCalculator // ---------------------------------------------------------------------- private ICalendarTimeRange FindLargestFreeTimeBlock(IEnumerable <ITimePeriod> reservations, ITimePeriod searchLimits = null, bool excludeWeekends = true) { TimePeriodCollection bookedPeriods = new TimePeriodCollection(reservations); if (searchLimits == null) { searchLimits = bookedPeriods; // use boundary of reservations } if (excludeWeekends) { Week currentWeek = new Week(searchLimits.Start); Week lastWeek = new Week(searchLimits.End); do { ITimePeriodCollection days = currentWeek.GetDays(); foreach (Day day in days) { if (!searchLimits.HasInside(day)) { continue; // outside of the search scope } if (day.DayOfWeek == DayOfWeek.Saturday || day.DayOfWeek == DayOfWeek.Sunday) { bookedPeriods.Add(day); // // exclude weekend day } } currentWeek = currentWeek.GetNextWeek(); } while (currentWeek.Start < lastWeek.Start); } // calculate the gaps using the time calendar as period mapper TimeGapCalculator <TimeRange> gapCalculator = new TimeGapCalculator <TimeRange>(new TimeCalendar()); ITimePeriodCollection freeTimes = gapCalculator.GetGaps(bookedPeriods, searchLimits); if (freeTimes.Count == 0) { return(null); } freeTimes.SortByDuration(); // move the largest gap to the start return(new CalendarTimeRange(freeTimes[0])); } // FindLargestFreeTimeBlock
/// <summary> /// Per Definition gilt das wenn mindestens eine Planzeit existiert das diese die KernzeitStart erfüllt /// Per Definition in der Planung können keine Lücken in der Kernzeit entstehen /// </summary> /// <param name="arbeitstag"></param> /// <param name="gruppe"></param> /// <param name="startzeitNichtAbgedeckt"></param> /// <param name="ticksNichtAbgedeckt"></param> /// <returns></returns> private static bool CheckKernzeitAbgedeckt(Arbeitstag arbeitstag, GruppenTyp gruppe, out DateTime startzeitNichtAbgedeckt, out short ticksNichtAbgedeckt) { startzeitNichtAbgedeckt = arbeitstag.KernzeitGruppeStart; ticksNichtAbgedeckt = (short)((arbeitstag.KernzeitGruppeEnde - arbeitstag.KernzeitGruppeStart).TotalMinutes / 15); if (!arbeitstag.CheckKernzeitAbgedeckt(gruppe)) { var planzeiten = new TimePeriodCollection(arbeitstag.GetMitarbeiterArbeitszeiten(gruppe)); var gapCalculator = new TimeGapCalculator <TimeRange>(new TimeCalendar()); var gap = gapCalculator.GetGaps(planzeiten, arbeitstag.KernzeitBasisRange).FirstOrDefault(); if (gap == null) { return(false); } startzeitNichtAbgedeckt = gap.Start; ticksNichtAbgedeckt = (short)(gap.Duration.TotalMinutes / 15); return(false); } return(true); }
// ---------------------------------------------------------------------- public IList<MyTimePeriod> GetGaps( IEnumerable<MyTimePeriod> periods ) { TimeGapCalculator<TimeRange> gapCalculator = new TimeGapCalculator<TimeRange>(); TimePeriodCollection calcPeriods = new TimePeriodCollection(); foreach ( MyTimePeriod period in periods ) { calcPeriods.Add( new TimeRange( period.Start, period.End ) ); } List<MyTimePeriod> gaps = new List<MyTimePeriod>(); if ( calcPeriods.Count == 0 ) { return gaps; } ITimePeriodCollection calcCaps = gapCalculator.GetGaps( calcPeriods ); foreach ( TimeRange calcCap in calcCaps ) { gaps.Add( new MyTimePeriod { Start = calcCap.Start, End = calcCap.End } ); } return gaps; }
public void OverlappingPeriods3Test() { var limits = new TimeRange(new DateTime(2011, 3, 29), new DateTime(2011, 4, 1)); var gapCalculator = new TimeGapCalculator<TimeRange>(); var excludePeriods = new TimePeriodCollection { new TimeRange(new DateTime(2011, 3, 30, 00, 00, 0), new DateTime(2011, 3, 31, 00, 00, 0)), new TimeRange(new DateTime(2011, 3, 30, 00, 00, 0), new DateTime(2011, 3, 31, 00, 00, 0)) }; ITimePeriodCollection gaps = gapCalculator.GetGaps(excludePeriods, limits); gaps.Count.Should().Be(2); Assert.IsTrue(gaps[0].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 29), new DateTime(2011, 3, 30)))); Assert.IsTrue(gaps[1].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 31), new DateTime(2011, 4, 01)))); }
// ---------------------------------------------------------------------- public ICalendarTimeRange FindLargestFreeTimeBlock( IEnumerable<ITimePeriod> reservations, ITimePeriod searchLimits = null, bool excludeWeekends = true) { TimePeriodCollection bookedPeriods = new TimePeriodCollection( reservations ); if ( searchLimits == null ) { searchLimits = bookedPeriods; // use boundary of reservations } if ( excludeWeekends ) { Week currentWeek = new Week( searchLimits.Start ); Week lastWeek = new Week( searchLimits.End ); do { ITimePeriodCollection days = currentWeek.GetDays(); foreach ( Day day in days ) { if ( !searchLimits.HasInside( day ) ) { continue; // outside of the search scope } if ( day.DayOfWeek == DayOfWeek.Saturday || day.DayOfWeek == DayOfWeek.Sunday ) { bookedPeriods.Add( day ); // // exclude weekend day } } currentWeek = currentWeek.GetNextWeek(); } while ( currentWeek.Start < lastWeek.Start ); } // calculate the gaps using the time calendar as period mapper TimeGapCalculator<TimeRange> gapCalculator = new TimeGapCalculator<TimeRange>( new TimeCalendar() ); ITimePeriodCollection freeTimes = gapCalculator.GetGaps( bookedPeriods, searchLimits ); if ( freeTimes.Count == 0 ) { return null; } freeTimes.SortByDuration(); // move the largest gap to the start return new CalendarTimeRange( freeTimes[ 0 ] ); }
public void MomentPeriodTest() { var limits = new TimeRange(new DateTime(2011, 3, 1), new DateTime(2011, 3, 20)); var gapCalculator = new TimeGapCalculator<TimeRange>(); var excludePeriods = new TimePeriodCollection { new TimeRange(new DateTime(2011, 3, 10), new DateTime(2011, 3, 10)) }; //! Gap 검사 시에 Moment는 제외된다!!! var gaps = gapCalculator.GetGaps(excludePeriods, limits); gaps.Count.Should().Be(1); gaps[0].IsSamePeriod(limits).Should().Be.True(); }
/// <summary> /// <paramref name="start"/>시각으로부터 <paramref name="offset"/> 만큼 떨어진 시각을 구합니다. /// </summary> /// <param name="start">기준 시각</param> /// <param name="offset">기간</param> /// <param name="seekDirection">검색 방향 (이전|이후)</param> /// <param name="seekBoundaryMode">검색 값 포함 여부</param> /// <param name="remaining">짜투리 기간</param> /// <returns>기준 시각으로터 오프셋만큼 떨어진 시각</returns> protected DateTime?CalculateEnd(DateTime start, TimeSpan offset, SeekDirection seekDirection, SeekBoundaryMode seekBoundaryMode, out TimeSpan?remaining) { if (IsDebugEnabled) { log.Debug("기준시각으로부터 오프셋만큼 떨어진 시각을 구합니다... " + @"start=[{0}], offset=[{1}], seekDirection=[{2}], seekBoundaryMode=[{3}]", start, offset, seekDirection, seekBoundaryMode); } Guard.Assert(offset >= TimeSpan.Zero, "offset 값은 항상 0 이상이어야 합니다. offset=[{0}]", offset); remaining = offset; // search periods ITimePeriodCollection searchPeriods = new TimePeriodCollection(IncludePeriods); if (searchPeriods.Count == 0) { searchPeriods.Add(TimeRange.Anytime); } // available periods ITimePeriodCollection availablePeriods = new TimePeriodCollection(); if (ExcludePeriods.Count == 0) { availablePeriods.AddAll(searchPeriods); } else { // 예외 기간을 제외합니다. // var gapCalculator = new TimeGapCalculator <TimeRange>(); var query = searchPeriods #if !SILVERLIGHT .AsParallel() .AsOrdered() #endif .SelectMany(searchPeriod => ExcludePeriods.HasOverlapPeriods(searchPeriod) ? gapCalculator.GetGaps(ExcludePeriods, searchPeriod) // 예외 기간과 검색 기간에서 겹치지 않는 기간을 계산하여, 추려냅니다. : new TimePeriodCollection { searchPeriod } // 예외 기간과 겹쳐진 부분이 없다면, 기간 전체를 추가합니다. ); availablePeriods.AddAll(query); } // 유효한 Period가 없다면 중단합니다. if (availablePeriods.Count == 0) { return(null); } // 기간중에 중복되는 부분의 없도록 유효한 기간을 결합합니다. if (availablePeriods.Count > 1) { var periodCombiner = new TimePeriodCombiner <TimeRange>(); availablePeriods = periodCombiner.CombinePeriods(availablePeriods); } // 첫 시작 기간을 찾습니다. // DateTime seekMoment; var startPeriod = (seekDirection == SeekDirection.Forward) ? FindNextPeriod(start, availablePeriods, out seekMoment) : FindPreviousPeriod(start, availablePeriods, out seekMoment); // 첫 시작 기간이 없다면 중단합니다. if (startPeriod == null) { return(null); } // 오프셋 값이 0 이라면, 바로 다음 값이므로 seekMoment를 반환합니다. if (offset == TimeSpan.Zero) { return(seekMoment); } if (seekDirection == SeekDirection.Forward) { for (var i = availablePeriods.IndexOf(startPeriod); i < availablePeriods.Count; i++) { var gap = availablePeriods[i]; var gapRemaining = gap.End - seekMoment; if (IsDebugEnabled) { log.Debug("Seek Forward... gap=[{0}], gapRemaining=[{1}], remaining=[{2}], seekMoment=[{3}]", gap, gapRemaining, remaining, seekMoment); } var isTargetPeriod = (seekBoundaryMode == SeekBoundaryMode.Fill) ? gapRemaining >= remaining : gapRemaining > remaining; if (isTargetPeriod) { var end = seekMoment + remaining.Value; remaining = null; return(end); } remaining = remaining - gapRemaining; if (i == availablePeriods.Count - 1) { return(null); } seekMoment = availablePeriods[i + 1].Start; // next period } } else { for (var i = availablePeriods.IndexOf(startPeriod); i >= 0; i--) { var gap = availablePeriods[i]; var gapRemaining = seekMoment - gap.Start; if (IsDebugEnabled) { log.Debug("Seek Backward... gap=[{0}], gapRemaining=[{1}], remaining=[{2}], seekMoment=[{3}]", gap, gapRemaining, remaining, seekMoment); } var isTargetPeriod = (seekBoundaryMode == SeekBoundaryMode.Fill) ? gapRemaining >= remaining : gapRemaining > remaining; if (isTargetPeriod) { var end = seekMoment - remaining.Value; remaining = null; return(end); } remaining = remaining - gapRemaining; if (i == 0) { return(null); } seekMoment = availablePeriods[i - 1].End; // previous period } } return(null); }
// ---------------------------------------------------------------------- private Week FindNextWeek( Week current ) { if ( ExcludePeriods.Count == 0 ) { return current.GetNextWeek(); } TimeRange limits = new TimeRange( current.End.AddTicks( 1 ), DateTime.MaxValue ); TimeGapCalculator<TimeRange> gapCalculator = new TimeGapCalculator<TimeRange>( calendar ); ITimePeriodCollection remainingPeriods = gapCalculator.GetGaps( ExcludePeriods, limits ); return remainingPeriods.Count > 0 ? new Week( remainingPeriods[ 0 ].Start ) : null; }
public void CalendarGetGapTest() { // simmulation of some reservations var periods = new TimePeriodCollection { new DayRangeCollection(2011, 3, 7, 2), new DayRangeCollection(2011, 3, 16, 2) }; // the overall search range var limits = new CalendarTimeRange(new DateTime(2011, 3, 4), new DateTime(2011, 3, 21)); var days = new DayRangeCollection(limits.Start, limits.Duration.Days + 1); // limits의 내부이고, 주말인 DayRange를 추가합니다. var excludeDays = days.GetDays().Where(day => limits.HasInside(day) && day.DayOfWeek.IsWeekEnd()); periods.AddAll(excludeDays.Cast<ITimePeriod>()); var gapCalculator = new TimeGapCalculator<TimeRange>(new TimeCalendar()); var gaps = gapCalculator.GetGaps(periods, limits); gaps.Count.Should().Be(4); gaps[0].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 4), DurationUtil.Days(1))).Should().Be.True(); gaps[1].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 9), DurationUtil.Days(3))).Should().Be.True(); gaps[2].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 14), DurationUtil.Days(2))).Should().Be.True(); gaps[3].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 18), DurationUtil.Days(1))).Should().Be.True(); }
public void SimleGapsTest() { var limits = new TimeRange(new DateTime(2011, 3, 1), new DateTime(2011, 3, 20)); var gapCalculator = new TimeGapCalculator<TimeRange>(); var excludeRange = new TimeRange(new DateTime(2011, 3, 10), new DateTime(2011, 3, 15)); var excludePeriods = new TimePeriodCollection { excludeRange }; var gaps = gapCalculator.GetGaps(excludePeriods, limits); gaps.Count.Should().Be(2); gaps[0].IsSamePeriod(new TimeRange(limits.Start, excludeRange.Start)).Should().Be.True(); gaps[1].IsSamePeriod(new TimeRange(excludeRange.End, limits.End)).Should().Be.True(); }
public void NoPeriodsTest() { TimeRange limits = new TimeRange( new DateTime( 2011, 3, 1 ), new DateTime( 2011, 3, 5 ) ); TimeGapCalculator<TimeRange> gapCalculator = new TimeGapCalculator<TimeRange>(); ITimePeriodCollection gaps = gapCalculator.GetGaps( new TimePeriodCollection(), limits ); Assert.AreEqual( gaps.Count, 1 ); Assert.IsTrue( gaps[ 0 ].IsSamePeriod( limits ) ); }
/// <summary> /// <paramref name="start"/>시각으로부터 <paramref name="offset"/> 만큼 떨어진 시각을 구합니다. /// </summary> /// <param name="start">기준 시각</param> /// <param name="offset">기간</param> /// <param name="seekDirection">검색 방향 (이전|이후)</param> /// <param name="seekBoundaryMode">검색 값 포함 여부</param> /// <param name="remaining">짜투리 기간</param> /// <returns>기준 시각으로터 오프셋만큼 떨어진 시각</returns> protected DateTime? CalculateEnd(DateTime start, TimeSpan offset, SeekDirection seekDirection, SeekBoundaryMode seekBoundaryMode, out TimeSpan? remaining) { if(IsDebugEnabled) log.Debug("기준시각으로부터 오프셋만큼 떨어진 시각을 구합니다... " + @"start=[{0}], offset=[{1}], seekDirection=[{2}], seekBoundaryMode=[{3}]", start, offset, seekDirection, seekBoundaryMode); Guard.Assert(offset >= TimeSpan.Zero, "offset 값은 항상 0 이상이어야 합니다. offset=[{0}]", offset); remaining = offset; // search periods ITimePeriodCollection searchPeriods = new TimePeriodCollection(IncludePeriods); if(searchPeriods.Count == 0) searchPeriods.Add(TimeRange.Anytime); // available periods ITimePeriodCollection availablePeriods = new TimePeriodCollection(); if(ExcludePeriods.Count == 0) { availablePeriods.AddAll(searchPeriods); } else { // 예외 기간을 제외합니다. // var gapCalculator = new TimeGapCalculator<TimeRange>(); var query = searchPeriods #if !SILVERLIGHT .AsParallel() .AsOrdered() #endif .SelectMany(searchPeriod => ExcludePeriods.HasOverlapPeriods(searchPeriod) ? gapCalculator.GetGaps(ExcludePeriods, searchPeriod) // 예외 기간과 검색 기간에서 겹치지 않는 기간을 계산하여, 추려냅니다. : new TimePeriodCollection { searchPeriod } // 예외 기간과 겹쳐진 부분이 없다면, 기간 전체를 추가합니다. ); availablePeriods.AddAll(query); } // 유효한 Period가 없다면 중단합니다. if(availablePeriods.Count == 0) return null; // 기간중에 중복되는 부분의 없도록 유효한 기간을 결합합니다. if(availablePeriods.Count > 1) { var periodCombiner = new TimePeriodCombiner<TimeRange>(); availablePeriods = periodCombiner.CombinePeriods(availablePeriods); } // 첫 시작 기간을 찾습니다. // DateTime seekMoment; var startPeriod = (seekDirection == SeekDirection.Forward) ? FindNextPeriod(start, availablePeriods, out seekMoment) : FindPreviousPeriod(start, availablePeriods, out seekMoment); // 첫 시작 기간이 없다면 중단합니다. if(startPeriod == null) return null; // 오프셋 값이 0 이라면, 바로 다음 값이므로 seekMoment를 반환합니다. if(offset == TimeSpan.Zero) return seekMoment; if(seekDirection == SeekDirection.Forward) { for(var i = availablePeriods.IndexOf(startPeriod); i < availablePeriods.Count; i++) { var gap = availablePeriods[i]; var gapRemaining = gap.End - seekMoment; if(IsDebugEnabled) log.Debug("Seek Forward... gap=[{0}], gapRemaining=[{1}], remaining=[{2}], seekMoment=[{3}]", gap, gapRemaining, remaining, seekMoment); var isTargetPeriod = (seekBoundaryMode == SeekBoundaryMode.Fill) ? gapRemaining >= remaining : gapRemaining > remaining; if(isTargetPeriod) { var end = seekMoment + remaining.Value; remaining = null; return end; } remaining = remaining - gapRemaining; if(i == availablePeriods.Count - 1) return null; seekMoment = availablePeriods[i + 1].Start; // next period } } else { for(var i = availablePeriods.IndexOf(startPeriod); i >= 0; i--) { var gap = availablePeriods[i]; var gapRemaining = seekMoment - gap.Start; if(IsDebugEnabled) log.Debug("Seek Backward... gap=[{0}], gapRemaining=[{1}], remaining=[{2}], seekMoment=[{3}]", gap, gapRemaining, remaining, seekMoment); var isTargetPeriod = (seekBoundaryMode == SeekBoundaryMode.Fill) ? gapRemaining >= remaining : gapRemaining > remaining; if(isTargetPeriod) { var end = seekMoment - remaining.Value; remaining = null; return end; } remaining = remaining - gapRemaining; if(i == 0) return null; seekMoment = availablePeriods[i - 1].End; // previous period } } return null; }
public void PeriodOutsideTouchingLimitsTest() { TimeRange limits = new TimeRange( new DateTime( 2011, 3, 1 ), new DateTime( 2011, 3, 31 ) ); TimeGapCalculator<TimeRange> gapCalculator = new TimeGapCalculator<TimeRange>(); TimePeriodCollection excludePeriods = new TimePeriodCollection(); excludePeriods.Add( new TimeRange( new DateTime( 2011, 2, 1 ), new DateTime( 2011, 3, 5 ) ) ); excludePeriods.Add( new TimeRange( new DateTime( 2011, 3, 20 ), new DateTime( 2011, 4, 15 ) ) ); ITimePeriodCollection gaps = gapCalculator.GetGaps( excludePeriods, limits ); Assert.AreEqual( gaps.Count, 1 ); Assert.IsTrue( gaps[ 0 ].IsSamePeriod( new TimeRange( new DateTime( 2011, 3, 5 ), new DateTime( 2011, 3, 20 ) ) ) ); }
public void PeriodLargerThanLimitsTest() { TimeRange limits = new TimeRange( new DateTime( 2011, 3, 1 ), new DateTime( 2011, 3, 5 ) ); TimeGapCalculator<TimeRange> gapCalculator = new TimeGapCalculator<TimeRange>(); TimePeriodCollection excludePeriods = new TimePeriodCollection(); excludePeriods.Add( new TimeRange( new DateTime( 2011, 2, 1 ), new DateTime( 2011, 4, 1 ) ) ); ITimePeriodCollection gaps = gapCalculator.GetGaps( excludePeriods, limits ); Assert.AreEqual( gaps.Count, 0 ); }
public void SimleGapsTest() { TimeRange limits = new TimeRange( new DateTime( 2011, 3, 1 ), new DateTime( 2011, 3, 20 ) ); TimeGapCalculator<TimeRange> gapCalculator = new TimeGapCalculator<TimeRange>(); TimePeriodCollection excludePeriods = new TimePeriodCollection(); excludePeriods.Add( new TimeRange( new DateTime( 2011, 3, 10 ), new DateTime( 2011, 3, 15 ) ) ); ITimePeriodCollection gaps = gapCalculator.GetGaps( excludePeriods, limits ); Assert.AreEqual( gaps.Count, 2 ); Assert.IsTrue( gaps[ 0 ].IsSamePeriod( new TimeRange( new DateTime( 2011, 3, 1 ), new DateTime( 2011, 3, 10 ) ) ) ); Assert.IsTrue( gaps[ 1 ].IsSamePeriod( new TimeRange( new DateTime( 2011, 3, 15 ), new DateTime( 2011, 3, 20 ) ) ) ); }
public void TouchingPeriodsTest() { TimeRange limits = new TimeRange( new DateTime( 2011, 3, 29 ), new DateTime( 2011, 4, 1 ) ); TimeGapCalculator<TimeRange> gapCalculator = new TimeGapCalculator<TimeRange>(); TimePeriodCollection excludePeriods = new TimePeriodCollection(); excludePeriods.Add( new TimeRange( new DateTime( 2011, 3, 30, 00, 00, 0 ), new DateTime( 2011, 3, 30, 08, 30, 0 ) ) ); excludePeriods.Add( new TimeRange( new DateTime( 2011, 3, 30, 08, 30, 0 ), new DateTime( 2011, 3, 30, 12, 00, 0 ) ) ); excludePeriods.Add( new TimeRange( new DateTime( 2011, 3, 30, 10, 00, 0 ), new DateTime( 2011, 3, 31, 00, 00, 0 ) ) ); ITimePeriodCollection gaps = gapCalculator.GetGaps( excludePeriods, limits ); Assert.AreEqual( gaps.Count, 2 ); Assert.IsTrue( gaps[ 0 ].IsSamePeriod( new TimeRange( new DateTime( 2011, 3, 29 ), new DateTime( 2011, 3, 30 ) ) ) ); Assert.IsTrue( gaps[ 1 ].IsSamePeriod( new TimeRange( new DateTime( 2011, 3, 31 ), new DateTime( 2011, 4, 01 ) ) ) ); }
public void TimeGapPrecisionSample() { TimePeriodCollection periods = new TimePeriodCollection(); periods.Add( new TimeRange( new DateTime( 2012, 3, 09, 0, 0, 00 ), new DateTime( 2012, 3, 09, 23, 59, 59 ) ) ); periods.Add( new TimeRange( new DateTime( 2012, 3, 10, 0, 0, 00 ), new DateTime( 2012, 3, 10, 23, 59, 59 ) ) ); periods.Add( new TimeRange( new DateTime( 2012, 3, 11, 0, 0, 10 ), new DateTime( 2012, 3, 11, 23, 59, 59 ) ) ); periods.Add( new TimeRange( new DateTime( 2012, 3, 12, 0, 0, 00 ), new DateTime( 2012, 3, 12, 23, 59, 59 ) ) ); // calculate the gaps using the time calendar as period mapper TimeGapCalculator<TimeRange> gapCalculator = new TimeGapCalculator<TimeRange>( new TimeCalendar( new TimeCalendarConfig { EndOffset = TimeSpan.Zero } ) ); ITimePeriodCollection freeTimes = gapCalculator.GetGaps( periods ); foreach ( TimeRange freeTime in freeTimes ) { Console.WriteLine( "free time : " + freeTime ); } }
/// <summary> /// <paramref name="current"/> 기준으로 예외기간 등을 고려한 선행의 WeekRange를 구합니다. /// </summary> /// <param name="current"></param> /// <returns></returns> private WeekRange FindPreviousWeek(WeekRange current) { if(IsDebugEnabled) log.Debug("현 Week [{0}]의 이전 Week 기간을 구합니다...", current); WeekRange result; if(ExcludePeriods.Count == 0) { result = current.GetPreviousWeek(); } else { var limits = new TimeRange(DateTime.MinValue, current.Start.AddTicks(-1)); var gapCalculator = new TimeGapCalculator<TimeRange>(TimeCalendar); var remainingPeriods = gapCalculator.GetGaps(ExcludePeriods, limits); result = (remainingPeriods.Count > 0) ? new WeekRange(remainingPeriods[remainingPeriods.Count - 1].End, TimeCalendar) : null; } if(IsDebugEnabled) log.Debug("현 Week의 이전 Week 기간을 구했습니다. current=[{0}], next=[{1}]", current, result); return result; }
/// <summary> /// <paramref name="fromTime"/> ~ <paramref name="toTime"/> 기간의 WorkingTime 의 기간을 구합니다. /// </summary> /// <param name="fromTime"></param> /// <param name="toTime"></param> /// <returns></returns> public TimeSpan Difference(DateTime fromTime, DateTime toTime) { if(IsDebugEnabled) log.Debug("fromTime[{0}] ~ toTime[{1}] 의 WorkingTime 기간을 구합니다.", fromTime, toTime); if(Equals(fromTime, toTime)) return TimeSpan.Zero; var filterIsEmpty = _collectorFilter.WeekDays.Count == 0 && _collectorFilter.CollectingHours.Count == 0 && _collectorFilter.CollectingDayHours.Count == 0; if(filterIsEmpty) return new DateDiff(fromTime, toTime, _calendar.Culture.Calendar, _calendar.FirstDayOfWeek, _calendar.YearBaseMonth) .Difference; var differenceRange = new TimeRange(fromTime, toTime); var collector = new CalendarPeriodCollector(_collectorFilter, new TimeRange(differenceRange.Start.Date, differenceRange.End.Date.AddDays(1)), SeekDirection.Forward, _calendar); // Gap을 계산합니다. var gapCalculator = new TimeGapCalculator<TimeRange>(_calendar); var gaps = gapCalculator.GetGaps(collector.Periods, differenceRange); var difference = gaps.Aggregate(TimeSpan.Zero, (current, gap) => current.Add(gap.Duration)); if(IsDebugEnabled) log.Debug("fromTime[{0}] ~ toTime[{1}] 의 WorkingTime 기간은 [{2}] 입니다!!!", fromTime, toTime, difference); return (fromTime < toTime) ? difference : difference.Negate(); }
public void GetGapTest() { var now = ClockProxy.Clock.Now; var schoolDay = new SchoolDay(now); var gapCalculator = new TimeGapCalculator<TimeRange>(); var excludePeriods = new TimePeriodCollection(); excludePeriods.AddAll(schoolDay); gapCalculator.GetGaps(excludePeriods).Count.Should().Be(0); gapCalculator.GetGaps(excludePeriods, schoolDay).Count.Should().Be(0); excludePeriods.Clear(); excludePeriods.Add(schoolDay.Lesson1); excludePeriods.Add(schoolDay.Lesson2); excludePeriods.Add(schoolDay.Lesson3); excludePeriods.Add(schoolDay.Lesson4); var gaps2 = gapCalculator.GetGaps(excludePeriods); gaps2.Count.Should().Be(3); gaps2[0].IsSamePeriod(schoolDay.Break1).Should().Be.True(); gaps2[1].IsSamePeriod(schoolDay.Break2).Should().Be.True(); gaps2[2].IsSamePeriod(schoolDay.Break3).Should().Be.True(); var testRange3 = new TimeRange(schoolDay.Lesson1.Start, schoolDay.Lesson4.End); var gaps3 = gapCalculator.GetGaps(excludePeriods, testRange3); gaps3.Count.Should().Be(3); gaps3[0].IsSamePeriod(schoolDay.Break1).Should().Be.True(); gaps3[1].IsSamePeriod(schoolDay.Break2).Should().Be.True(); gaps3[2].IsSamePeriod(schoolDay.Break3).Should().Be.True(); var testRange4 = new TimeRange(schoolDay.Start.AddHours(-1), schoolDay.End.AddHours(1)); var gaps4 = gapCalculator.GetGaps(excludePeriods, testRange4); gaps4.Count.Should().Be(5); gaps4[0].IsSamePeriod(new TimeRange(testRange4.Start, schoolDay.Start)).Should().Be.True(); gaps4[1].IsSamePeriod(schoolDay.Break1).Should().Be.True(); gaps4[2].IsSamePeriod(schoolDay.Break2).Should().Be.True(); gaps4[3].IsSamePeriod(schoolDay.Break3).Should().Be.True(); gaps4[4].IsSamePeriod(new TimeRange(testRange4.End, schoolDay.End)).Should().Be.True(); excludePeriods.Clear(); excludePeriods.Add(schoolDay.Lesson1); var gaps8 = gapCalculator.GetGaps(excludePeriods, schoolDay.Lesson1); gaps8.Count.Should().Be(0); excludePeriods.Clear(); excludePeriods.Add(schoolDay.Lesson1); var testRange9 = new TimeRange(schoolDay.Lesson1.Start.Subtract(new TimeSpan(1)), schoolDay.Lesson1.End.Add(new TimeSpan(1))); var gaps9 = gapCalculator.GetGaps(excludePeriods, testRange9); gaps9.Count.Should().Be(2); gaps9[0].Duration.Should().Be(TimeSpan.FromTicks(1)); gaps9[1].Duration.Should().Be(TimeSpan.FromTicks(1)); }
// ---------------------------------------------------------------------- protected DateTime? CalculateEnd( DateTime start, TimeSpan offset, SeekDirection seekDirection, SeekBoundaryMode seekBoundaryMode, out TimeSpan? remaining) { if ( offset < TimeSpan.Zero ) { throw new InvalidOperationException( "time span must be positive" ); } remaining = offset; // search periods TimePeriodCollection searchPeriods = new TimePeriodCollection( includePeriods ); // no search periods specified: search anytime if ( searchPeriods.Count == 0 ) { searchPeriods.Add( TimeRange.Anytime ); } // available periods ITimePeriodCollection availablePeriods = new TimePeriodCollection(); // no exclude periods specified: use all search periods if ( excludePeriods.Count == 0 ) { availablePeriods.AddAll( searchPeriods ); } else // remove exclude periods { TimeGapCalculator<TimeRange> gapCalculator = new TimeGapCalculator<TimeRange>(); foreach ( ITimePeriod searchPeriod in searchPeriods ) { // no overlaps: use the entire search range if ( !excludePeriods.HasOverlapPeriods( searchPeriod ) ) { availablePeriods.Add( searchPeriod ); } else // add gaps of search period using the exclude periods { availablePeriods.AddAll( gapCalculator.GetGaps( excludePeriods, searchPeriod ) ); } } } // no periods available if ( availablePeriods.Count == 0 ) { return null; } // combine the available periods, ensure no overlapping // used for FindNextPeriod/FindPreviousPeriod if ( availablePeriods.Count > 1 ) { TimePeriodCombiner<TimeRange> periodCombiner = new TimePeriodCombiner<TimeRange>(); availablePeriods = periodCombiner.CombinePeriods( availablePeriods ); } // find the starting search period ITimePeriod startPeriod = null; DateTime seekMoment = start; switch ( seekDirection ) { case SeekDirection.Forward: startPeriod = FindNextPeriod( start, availablePeriods, out seekMoment ); break; case SeekDirection.Backward: startPeriod = FindPreviousPeriod( start, availablePeriods, out seekMoment ); break; } // no starting period available if ( startPeriod == null ) { return null; } // no offset: use the search staring position // maybe moved to the next available search period if ( offset == TimeSpan.Zero ) { return seekMoment; } // setup destination search switch ( seekDirection ) { case SeekDirection.Forward: for ( int i = availablePeriods.IndexOf( startPeriod ); i < availablePeriods.Count; i++ ) { ITimePeriod gap = availablePeriods[ i ]; TimeSpan gapRemining = gap.End - seekMoment; bool isTargetPeriod = false; switch ( seekBoundaryMode ) { case SeekBoundaryMode.Fill: isTargetPeriod = gapRemining >= remaining; break; case SeekBoundaryMode.Next: isTargetPeriod = gapRemining > remaining; break; } if ( isTargetPeriod ) { DateTime end = seekMoment + remaining.Value; remaining = null; return end; } remaining = remaining - gapRemining; if ( i == availablePeriods.Count - 1 ) { return null; } seekMoment = availablePeriods[ i + 1 ].Start; // next period } break; case SeekDirection.Backward: for ( int i = availablePeriods.IndexOf( startPeriod ); i >= 0; i-- ) { ITimePeriod gap = availablePeriods[ i ]; TimeSpan gapRemining = seekMoment - gap.Start; bool isTargetPeriod = false; switch ( seekBoundaryMode ) { case SeekBoundaryMode.Fill: isTargetPeriod = gapRemining >= remaining; break; case SeekBoundaryMode.Next: isTargetPeriod = gapRemining > remaining; break; } if ( isTargetPeriod ) { DateTime end = seekMoment - remaining.Value; remaining = null; return end; } remaining = remaining - gapRemining; if ( i == 0 ) { return null; } seekMoment = availablePeriods[ i - 1 ].End; // previous period } break; } return null; }
/// <summary> /// <paramref name="current"/> 기준으로 예외 기간 등을 고려한 후행의 가장 근접한 WeekRange를 구합니다. /// </summary> /// <param name="current"></param> /// <returns></returns> private WeekRange FindNextWeek(WeekRange current) { if(IsDebugEnabled) log.Debug("현 Week [{0}]의 다음 Week 기간을 구합니다...", current); WeekRange result; if(ExcludePeriods.Count == 0) { result = current.GetNextWeek(); } else { var limits = new TimeRange(current.End.AddTicks(1), DateTime.MaxValue); var gapCalculator = new TimeGapCalculator<TimeRange>(TimeCalendar); var remainingPeriods = gapCalculator.GetGaps(ExcludePeriods, limits); result = (remainingPeriods.Count > 0) ? new WeekRange(remainingPeriods[0].Start, TimeCalendar) : null; } if(IsDebugEnabled) log.Debug("현 Week의 다음 Week 기간을 구했습니다. current=[{0}], next=[{1}]", current, result); return result; }
// ---------------------------------------------------------------------- private Week FindPreviousWeek( Week current ) { if ( ExcludePeriods.Count == 0 ) { return current.GetPreviousWeek(); } TimeRange limits = new TimeRange( DateTime.MinValue, current.Start.AddTicks( -1 ) ); TimeGapCalculator<TimeRange> gapCalculator = new TimeGapCalculator<TimeRange>( calendar ); ITimePeriodCollection remainingPeriods = gapCalculator.GetGaps( ExcludePeriods, limits ); return remainingPeriods.Count > 0 ? new Week( remainingPeriods[ remainingPeriods.Count - 1 ].End ) : null; }
public void PeriodTouchingLimitsStartTest() { var limits = new TimeRange(new DateTime(2011, 3, 1), new DateTime(2011, 3, 20)); var gapCalculator = new TimeGapCalculator<TimeRange>(); var excludePeriods = new TimePeriodCollection { new TimeRange(new DateTime(2011, 3, 1), new DateTime(2011, 3, 10)) }; var gaps = gapCalculator.GetGaps(excludePeriods, limits); gaps.Count.Should().Be(1); gaps[0].IsSamePeriod(new TimeRange(new DateTime(2011, 3, 10), new DateTime(2011, 3, 20))).Should().Be.True(); }
// ---------------------------------------------------------------------- public TimeSpan Difference( DateTime date1, DateTime date2 ) { if ( date1.Equals( date2 ) ) { return TimeSpan.Zero; } if ( collectorFilter.WeekDays.Count == 0 && collectorFilter.CollectingHours.Count == 0 && collectorFilter.CollectingDayHours.Count == 0 ) { return new DateDiff( date1, date2, calendar.Culture.Calendar, calendar.FirstDayOfWeek, calendar.YearBaseMonth ).Difference; } TimeRange differenceRange = new TimeRange( date1, date2 ); CalendarPeriodCollector collector = new CalendarPeriodCollector( collectorFilter, new TimeRange( differenceRange.Start.Date, differenceRange.End.Date.AddDays( 1 ) ), SeekDirection.Forward, calendar ); collector.CollectHours(); // calculate gaps TimeGapCalculator<TimeRange> gapCalculator = new TimeGapCalculator<TimeRange>( calendar ); ITimePeriodCollection gaps = gapCalculator.GetGaps( collector.Periods, differenceRange ); // calculate difference (sum gap durations) TimeSpan difference = TimeSpan.Zero; foreach ( ITimePeriod gap in gaps ) { difference = difference.Add( gap.Duration ); } return date1 < date2 ? difference : difference.Negate(); }