Example #1
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 = gaps.GetTotalDuration(DurationProvider);

            return(date1 < date2 ? difference : difference.Negate());
        }
 public TimePeriodSubtractor(ITimePeriodMapper periodMapper)
 {
     this.PeriodMapper      = periodMapper;
     _timePeriodCombiner    = new TimePeriodCombiner <T>(periodMapper);
     _timeGapCalculator     = new TimeGapCalculator <T>(periodMapper);
     _timePeriodIntersector = new TimePeriodIntersector <T>(periodMapper);
 }
Example #3
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);
        }
Example #4
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);
        }
Example #5
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);
        }