Example #1
0
        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
Example #2
0
        }         // 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
Example #3
0
        public static void TestTimeGap()
        {
            var schedule = new TimeBlock(new DateTime(2018, 10, 10, 08, 30, 00), Duration.Minutes(180));
            var bookings = new TimePeriodCollection
            {
                new TimeRange(new DateTime(2018, 10, 10, 08, 00, 0), Duration.Minutes(60)),
                new TimeRange(new DateTime(2018, 10, 10, 09, 30, 0), Duration.Minutes(30)),
                new TimeRange(new DateTime(2018, 10, 10, 10, 00, 0), Duration.Minutes(30)),
            };
            var selected = new TimeBlock(new DateTime(2018, 10, 10, 09, 30, 0), Duration.Minutes(30));

            Console.WriteLine($"Selected: {selected}");
            Console.WriteLine();

            // calculate the gaps using the time calendar as period mapper
            var availableTimes = new TimeGapCalculator <TimeBlock>()
                                 .GetGaps(bookings, schedule)
                                 .Where(t => t.Duration >= selected.Duration)
                                 .SelectMany(t => t.Split(selected.Duration));

            foreach (var t in availableTimes)
            {
                Console.WriteLine($"Result: {t}");
            }
        }
Example #4
0
        /// <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);
        }
        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 ) ) ) );
        }
Example #6
0
        /// <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);
        }
        // ----------------------------------------------------------------------
        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 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();
        }
Example #9
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
Example #10
0
        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 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
Example #13
0
        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 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 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 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
Example #17
0
        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
Example #18
0
        /// <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();
        }
Example #20
0
        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
Example #21
0
        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
Example #22
0
        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);
        }
        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
Example #24
0
        }         // 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
Example #25
0
        /// <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))));
        }
Example #28
0
        // ----------------------------------------------------------------------
        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();
        }
Example #30
0
        /// <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);
        }
Example #31
0
        // ----------------------------------------------------------------------
        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();
        }
Example #33
0
        /// <summary>
        ///     Generate a <see cref="CompletenessReport" /> for the given parameters.
        /// </summary>
        /// <param name="em">Energiemenge</param>
        /// <param name="reference">reference time frame</param>
        /// <param name="wev">Wertermittlungsverfahren</param>
        /// <param name="obiskennzahl">OBIS Kennzahl</param>
        /// <param name="einheit">Mengeneinheit</param>
        /// <returns>the completeness report</returns>
        public static CompletenessReport GetCompletenessReport(this BO.Energiemenge em, ITimeRange reference,
                                                               Wertermittlungsverfahren wev, string obiskennzahl, Mengeneinheit einheit)
        {
            CompletenessReport result;

            using (MiniProfiler.Current.Step("create completeness report skeleton + find the coverage"))
            {
                result = new CompletenessReport
                {
                    LokationsId = em.LokationsId,
                    Einheit     = einheit,
                    Coverage    = GetCoverage(em, reference, wev, obiskennzahl, einheit),
                    Wertermittlungsverfahren = wev,
                    Obiskennzahl             = obiskennzahl,
                    ReferenceTimeFrame       = new Zeitraum
                    {
                        Startdatum = new DateTimeOffset(DateTime.SpecifyKind(reference.Start, DateTimeKind.Utc)),
                        Enddatum   = new DateTimeOffset(DateTime.SpecifyKind(reference.End, DateTimeKind.Utc))
                    }
                };
            }

            if (em.Energieverbrauch != null && em.Energieverbrauch.Any())
            {
                /*using (MiniProfiler.Current.Step("populating time slices of/with missing/null values"))
                 * {
                 *  result.values = em.GetMissingTimeRanges(reference, wev, obis, einheit)
                 *      .Select(mtr => new CompletenessReport.BasicVerbrauch
                 *      {
                 *          startdatum = DateTime.SpecifyKind(mtr.Start, DateTimeKind.Utc),
                 *          enddatum = DateTime.SpecifyKind(mtr.End, DateTimeKind.Utc),
                 *          wert = null
                 *      }).ToList<CompletenessReport.BasicVerbrauch>();
                 * }
                 * using (MiniProfiler.Current.Step("populating time slices existing values"))
                 * {
                 *  result.values.AddRange(
                 *  em.energieverbrauch
                 *  //.AsParallel<Verbrauch>()
                 *  .Where(v => v.obiskennzahl == obis && v.einheit == einheit && v.wertermittlungsverfahren == wev)
                 *  .Select(v => new CompletenessReport.BasicVerbrauch
                 *  {
                 *      startdatum = DateTime.SpecifyKind(v.startdatum, DateTimeKind.Utc),
                 *      enddatum = DateTime.SpecifyKind(v.enddatum, DateTimeKind.Utc),
                 *      wert = v.wert
                 *  })
                 *  .ToList<CompletenessReport.BasicVerbrauch>());
                 * }*/
                using (MiniProfiler.Current.Step("Setting aggregated gaps"))
                {
                    var nonNullValues =
                        new TimePeriodCollection(
                            em.Energieverbrauch.Select(v => new TimeRange(v.Startdatum, v.Enddatum)));
                    ITimeRange limits;
                    if (result.ReferenceTimeFrame != null && result.ReferenceTimeFrame.Startdatum.HasValue)
                    {
                        limits = new TimeRange(result.ReferenceTimeFrame.Startdatum.Value.UtcDateTime,
                                               result.ReferenceTimeFrame.Enddatum.Value.UtcDateTime);
                    }
                    else
                    {
                        limits = null;
                    }
                    var gaps = new TimeGapCalculator <TimeRange>().GetGaps(nonNullValues, limits);
                    result.Gaps = gaps.Select(gap => new CompletenessReport.BasicVerbrauch
                    {
                        Startdatum = gap.Start,
                        Enddatum   = gap.End,
                        Wert       = null
                    }).ToList();
                }

                /*using (MiniProfiler.Current.Step("sorting result"))
                 * {
                 *  result.values.Sort(new BasicVerbrauchDateTimeComparer());
                 * }*/
                if (em.IsPure(true))
                {
                    try
                    {
                        foreach (var kvp in em.Energieverbrauch.Where(v => v.UserProperties != null)
                                 .SelectMany(v => v.UserProperties))
                        {
                            if (result.UserProperties == null)
                            {
                                result.UserProperties = new Dictionary <string, object>();
                            }
                            if (!result.UserProperties.ContainsKey(kvp.Key))
                            {
                                result.UserProperties.Add(kvp.Key, kvp.Value);
                            }
                        }
                    }
                    catch (InvalidOperationException)
                    {
                        // ok, there's no Verbrauch with user properties.
                    }
                }
            }

            /*else
             * {
             *  result.coverage = null;
             *  result._errorMessage = "energieverbrauch is empty";
             * }*/
            return(result);
        }
        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 ) );
        }
Example #35
0
        /// <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 ) ) ) );
        }
Example #40
0
        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 );
            }
        }
Example #41
0
        /// <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;
        }
Example #42
0
        /// <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));
        }
Example #44
0
        // ----------------------------------------------------------------------
        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;
        }
Example #45
0
        /// <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;
        }
Example #46
0
        // ----------------------------------------------------------------------
        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();
        }
Example #48
0
        // ----------------------------------------------------------------------
        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();
        }