/// <summary> /// 시작시각과 완료시각을 지정된 기간 정보를 기준으로 변경합니다. /// </summary> /// <param name="period"></param> public virtual void ExpandTo(ITimePeriod period) { period.ShouldNotBeNull("period"); ExpandStartTo(period.Start); ExpandEndTo(period.End); }
public void Add(ITimePeriod period) { period.ShouldNotBeNull("period"); AddPeriod(period.Start, period); AddPeriod(period.End, period); }
/// <summary> /// 기간을 지정한 기간으로 축소시킵니다. /// </summary> /// <param name="period"></param> public virtual void ShrinkTo(ITimePeriod period) { period.ShouldNotBeNull("period"); ShrinkStartTo(period.Start); ShrinkEndTo(period.End); }
/// <summary> /// <paramref name="period"/> 기간 내에서 예외 기간등을 제외한 기간들을 HourRange 컬렉션으로 단위로 반환합니다. /// </summary> /// <param name="period"></param> /// <returns></returns> private IEnumerable <ITimePeriod> GetAvailableWeekPeriods(ITimePeriod period) { period.ShouldNotBeNull("period"); if (WeekDays.Count == 0 && WorkingHours.Count == 0 && WorkingDayHours.Count == 0) { return new TimePeriodCollection { period } } ; // 필터에 필터링할 정보를 추가합니다. // var filter = new CalendarPeriodCollectorFilter(); WeekDays.RunEach(weekDay => filter.WeekDays.Add(weekDay)); WorkingHours.RunEach(workingHour => filter.CollectingHours.Add(workingHour)); WorkingDayHours.RunEach(workingDayHour => filter.CollectingDayHours.Add(workingDayHour)); var weekCollector = new CalendarPeriodCollector(filter, period, SeekDirection.Forward, TimeCalendar); weekCollector.CollectHours(); return(weekCollector.Periods); } }
/// <summary> /// Copy Constructor /// </summary> /// <param name="source">복사할 원본 ITimePeriod</param> protected TimePeriodBase(ITimePeriod source) { source.ShouldNotBeNull("source"); _start = source.Start; _end = source.End; IsReadOnly = source.IsReadOnly; }
/// <summary> /// 기간 단위에 따라 Category를 생성합니다. /// </summary> /// <param name="categoryCollectionList">생성된 <see cref="CategoriesElement"/> 정보가 담길 객체</param> /// <param name="timePeriod">Gantt에 표현할 전체 기간 (프로젝트 전체 기간)</param> /// <param name="periodFlags">Gantt Chart X축에 나타낼 기간 단위 정보</param> public static void GenerateCategories(IList <CategoriesElement> categoryCollectionList, ITimePeriod timePeriod, PeriodFlags periodFlags) { categoryCollectionList.ShouldNotBeNull("categoryCollectionList"); timePeriod.ShouldNotBeNull("periodRange"); Guard.Assert(timePeriod.HasPeriod, "Gantt에 나타낼 전체 기간은 시작과 끝이 있어야합니다."); if (IsDebugEnabled) { log.Debug("Gantt의 기간 부분을 생성합니다. timePeriod=[{0}], periodFlags=[{1}]", timePeriod, periodFlags); } categoryCollectionList.Clear(); if ((periodFlags & PeriodFlags.Year) > 0) { categoryCollectionList.Add(CreateCategories(timePeriod.ForEachYears(), range => range.Start.Year.ToString())); } if ((periodFlags & PeriodFlags.HalfYear) > 0) { categoryCollectionList.Add(CreateCategories(timePeriod.ForEachYears(), range => (range.End.HalfyearOf() == HalfyearKind.First) ? "1st" : "2nd")); } if ((periodFlags & PeriodFlags.Quarter) > 0) { categoryCollectionList.Add(CreateCategories(timePeriod.ForEachQuarters(), range => "Q" + range.End.QuarterOf().GetHashCode().ToString())); } if ((periodFlags & PeriodFlags.Month) > 0) { categoryCollectionList.Add(CreateCategories(timePeriod.ForEachMonths(), range => range.End.GetMonthName())); } if ((periodFlags & PeriodFlags.Week) > 0) { categoryCollectionList.Add(CreateCategories(timePeriod.ForEachWeeks(), range => "W" + range.End.GetYearAndWeek().Week.Value.ToString())); } if ((periodFlags & PeriodFlags.Day) > 0) { categoryCollectionList.Add(CreateCategoriesAsParallel(timePeriod.ForEachDays(), range => range.End.Day.ToString())); } if ((periodFlags & PeriodFlags.Hour) > 0) { categoryCollectionList.Add(CreateCategoriesAsParallel(timePeriod.ForEachHours(), range => "H" + range.End.Hour.ToString())); } }
protected CalendarVisitor(TFilter filter, ITimePeriod limits, SeekDirection?seekDirection, ITimeCalendar calendar) { filter.ShouldNotBeNull("filter"); limits.ShouldNotBeNull("limits"); Filter = filter; Limits = limits; SeekDirection = seekDirection ?? SeekDirection.Forward; Calendar = calendar; }
/// <summary> /// 생성자 /// </summary> /// <param name="calendar"></param> /// <param name="timeRange"></param> /// <param name="previousCumulatedWorkInMinute"></param> public WorkTimeByRange(Calendar calendar, ITimePeriod timeRange, int previousCumulatedWorkInMinute) : base(calendar, timeRange.Start) { timeRange.ShouldNotBeNull("timeRange"); Guard.Assert(timeRange.HasPeriod, @"timeRange는 명시적인 구간을 가져야 합니다."); TimePeriod.Setup(timeRange.Start, timeRange.End); CumulatedInMinute = previousCumulatedWorkInMinute + WorkInMinute; }
/// <summary> /// 주어진 기간이 오버랩되는지를 파악하는 질의어를 빌드합니다. (모든 구간은 폐쇄구간일 필요는 없고, 개방 구간이라도 상관없습니다. /// </summary> /// <typeparam name="T">엔티티 수형</typeparam> /// <param name="period">검사할 시간 구간</param> /// <param name="loExpr">하한값을 나타내는 속성</param> /// <param name="hiExpr">상한값을 나타내는 속성</param> /// <returns></returns> public static ICriterion IsOverlapCriterion <T>(this ITimePeriod period, Expression <Func <T, object> > loExpr, Expression <Func <T, object> > hiExpr) { period.ShouldNotBeNull("period"); Guard.Assert(period.IsAnytime == false, @"기간이 설정되어 있지 않습니다. 상하한 값 모두 없으므로, 질의어를 만들 필요가 없습니다."); var loPropertyName = RetrievePropertyName(loExpr); var hiPropertyName = RetrievePropertyName(hiExpr); return(CriteriaTool.IsOverlapCriterion(period, loPropertyName, hiPropertyName)); }
public TimeInterval(ITimePeriod src) : base(src) { src.ShouldNotBeNull("src"); var interval = src as ITimeInterval; if(interval != null) { _start = interval.StartInterval; _end = interval.EndInterval; _startEdge = interval.StartEdge; _endEdge = interval.EndEdge; _isIntervalEnabled = interval.IsIntervalEnabled; } }
/// <summary> /// 지정된 기간(<paramref name="period"/>)을 <paramref name="periodKind"/> 단위로 열거하면서, <paramref name="runner"/>을 실행합니다. /// </summary> /// <typeparam name="T">실행한 결과 값의 수형</typeparam> /// <param name="period">전체 기간</param> /// <param name="periodKind">열거할 기간의 단위</param> /// <param name="runner">각 단위 기간별 실행할 델리게이트</param> /// <returns>각 단위 기간별 실행 결과</returns> /// <example> /// <code> /// var calendar = CultureInfo.CurrentCulture.Calendar; /// var results = RunEach(new YearRange(DateTime.Now), PeriodKind.Day, (day)=>calendar.GetDaysOfYear(day.Start)); /// </code> /// </example> public static IEnumerable <T> RunPeriod <T>(this ITimePeriod period, PeriodKind periodKind, Func <ITimePeriod, T> runner) { period.ShouldNotBeNull("period"); runner.ShouldNotBeNull("runner"); Guard.Assert(period.HasPeriod, "period는 기간을 가져야 합니다. period=" + period); if (IsDebugEnabled) { log.Debug("기간[{0}] 을 [{1}] 단위로 열거하고, 함수를 실행합니다.", period, periodKind); } return(ForEachPeriods(period, periodKind).Select(p => runner(p))); }
/// <summary> /// <paramref name="period"/>가 <paramref name="target"/>과의 시간 축으로 선 후행 관계를 판단합니다. /// </summary> /// <param name="period"></param> /// <param name="target"></param> /// <returns></returns> public static PeriodRelation GetReleation(this ITimePeriod period, ITimePeriod target) { period.ShouldNotBeNull("period"); target.ShouldNotBeNull("target"); var relation = PeriodRelation.NoRelation; if(period.Start > target.End) { relation = PeriodRelation.After; } else if(period.End < target.Start) { relation = PeriodRelation.Before; } else if(period.Start == target.Start && period.End == target.End) { relation = PeriodRelation.ExactMatch; } else if(period.Start == target.End) { relation = PeriodRelation.StartTouching; } else if(period.End == target.Start) { relation = PeriodRelation.EndTouching; } else if(HasInside(period, target)) { if(period.Start == target.Start) relation = PeriodRelation.EnclosingStartTouching; else relation = (period.End == target.End) ? PeriodRelation.EnclosingEndTouching : PeriodRelation.Enclosing; } // 기간이 대상 기간 내부에 속할 때 else { var insideStart = HasInside(target, period.Start); var insideEnd = HasInside(target, period.End); if(insideStart && insideEnd) { relation = Equals(period.Start, target.Start) ? PeriodRelation.InsideStartTouching : period.End == target.End ? PeriodRelation.InsideEndTouching : PeriodRelation.Inside; } else if(insideStart) relation = PeriodRelation.StartInside; else if(insideEnd) relation = PeriodRelation.EndInside; } if(IsDebugEnabled) log.Debug("period[{0}]와 target[{1}] 간의 Relation은 [{2}] 입니다.", period.AsString(), target.AsString(), relation); return relation; }
/// <summary> /// 지정된 기간(<paramref name="period"/>)을 <paramref name="periodKind"/> 단위로 열거하면서, <paramref name="runner"/>을 비동기 방식으로 실행합니다. /// </summary> /// <typeparam name="T">실행한 결과 값의 수형</typeparam> /// <param name="period">전체 기간</param> /// <param name="periodKind">열거할 기간의 단위</param> /// <param name="runner">각 단위 기간별 실행할 델리게이트</param> /// <returns>각 단위 기간별 실행 결과</returns> /// <example> /// <code> /// var calendar = CultureInfo.CurrentCulture.Calendar; /// var results = RunEachAsync(new YearRange(DateTime.Now), PeriodKind.Day, (day)=>calendar.GetDaysOfYear(day.Start)); /// </code> /// </example> /// <seealso cref="EnumerableTool.RunEachAsync{T,TResult}"/> public static IEnumerable <T> RunPeriodAsync <T>(this ITimePeriod period, PeriodKind periodKind, Func <ITimePeriod, T> runner) { period.ShouldNotBeNull("period"); runner.ShouldNotBeNull("runner"); AssertHasPeriod(period); if (IsDebugEnabled) { log.Debug("기간[{0}] 을 [{1}] 단위로 열거하고, 비동기 방식으로 함수를 실행합니다.", period, periodKind); } return(ForEachPeriods(period, periodKind).RunEachAsync(runner)); }
public TimeInterval(ITimePeriod src) : base(src) { src.ShouldNotBeNull("src"); var interval = src as ITimeInterval; if (interval != null) { _start = interval.StartInterval; _end = interval.EndInterval; _startEdge = interval.StartEdge; _endEdge = interval.EndEdge; _isIntervalEnabled = interval.IsIntervalEnabled; } }
/// <summary> /// 시작시각과 완료시각을 지정된 기간 정보를 기준으로 변경합니다. /// </summary> /// <param name="period"></param> public void ExpandTo(ITimePeriod period) { period.ShouldNotBeNull("period"); AssertMutable(); if (period.HasStart) { ExpandStartTo(period.Start); } if (period.HasEnd) { ExpandEndTo(period.End); } }
/// <summary> /// 두 기간 교차하거나, <paramref name="period"/>가 <paramref name="target"/> 의 내부 구간이면 true를 반환합니다. /// </summary> /// <param name="period"></param> /// <param name="target"></param> /// <returns></returns> public static bool IntersectsWith(this ITimePeriod period, ITimePeriod target) { target.ShouldNotBeNull("target"); var isIntersected = period.HasInside(target.Start) || period.HasInside(target.End) || (target.Start <period.Start && target.End> period.End); if (IsDebugEnabled) { log.Debug("period[{0}]와 target[{1}]이 교차 구간이 있는지 확인합니다. isIntersected=[{2}]", period.AsString(), target.AsString(), isIntersected); } return(isIntersected); }
/// <summary> /// TimePeriodChain에서 요소 <paramref name="item"/>을 제거합니다. (제거된 후의 후속 Period들의 시간이 조정됩니다) /// </summary> /// <param name="item"></param> /// <returns></returns> public override bool Remove(ITimePeriod item) { item.ShouldNotBeNull("item"); if (Count <= 0) { return(false); } if (IsDebugEnabled) { log.Debug("요소[{0}] 를 제거하려고 합니다...", item); } var itemDuration = item.Duration; var index = IndexOf(item); ITimePeriod next = null; if (itemDuration > TimeSpan.Zero && index > 0 && index < Count - 1) { next = this[index]; } var removed = _periods.Remove(item); if (removed && next != null) { if (IsDebugEnabled) { log.Debug("요소[{0}]를 제거하고, Chain의 후속 Period 들의 기간을 조정합니다...", item); } for (int i = index; i < Count; i++) { var start = this[i].Start.Subtract(itemDuration); this[i].Setup(start, start.Add(this[i].Duration)); } } if (IsDebugEnabled) { log.Debug("요소[{0}] 를 제거 결과=[{1}]", item, removed); } return(removed); }
/// <summary> /// 지정된 기간을 <paramref name="mapper"/>를 통해 매핑한 기간으로 반환합니다. /// </summary> /// <param name="period"></param> /// <param name="mapper"></param> /// <returns></returns> private static TimeRange ToCalendarTimeRange(ITimePeriod period, ITimePeriodMapper mapper) { period.ShouldNotBeNull("period"); mapper = mapper ?? new TimeCalendar(); var mappedStart = mapper.MapStart(period.Start); var mappedEnd = mapper.MapEnd(period.End); TimeTool.AssertValidPeriod(mappedStart, mappedEnd); var mapped = new TimeRange(mappedStart, mappedEnd); if (IsDebugEnabled) { log.Debug("TimeCalendar 기준의 기간으로 매핑했습니다. period=[{0}], mapped=[{1}]", period, mapped); } return(mapped); }
/// <summary> /// 지정된 기간(<paramref name="period"/>)을 <paramref name="periodKind"/> 단위로 열거하면서, 병렬로 <paramref name="runner"/>을 실행합니다. /// </summary> /// <typeparam name="T">실행한 결과 값의 수형</typeparam> /// <param name="period">전체 기간</param> /// <param name="periodKind">열거할 기간의 단위</param> /// <param name="runner">각 단위 기간별 실행할 델리게이트</param> /// <returns>각 단위 기간별 실행 결과</returns> /// <example> /// <code> /// var calendar = CultureInfo.CurrentCulture.Calendar; /// var results = RunEachAsParallel(new YearRange(DateTime.Now), PeriodKind.Day, (day)=>calendar.GetDaysOfYear(day.Start)); /// </code> /// </example> public static IEnumerable <T> RunPeriodAsParallel <T>(this ITimePeriod period, PeriodKind periodKind, Func <ITimePeriod, T> runner) { period.ShouldNotBeNull("period"); runner.ShouldNotBeNull("runner"); AssertHasPeriod(period); if (IsDebugEnabled) { log.Debug("기간[{0}] 을 [{1}] 단위로 열거하고, 병렬로 함수를 실행합니다.", period, periodKind); } return (ForEachPeriods(period, periodKind) #if !SILVERLIGHT .AsParallel() .AsOrdered() #endif .Select(p => runner(p))); }
/// <summary> /// 새로운 <paramref name="item"/>을 Chain의 제일 끝에 붙여 넣습니다. <paramref name="item"/>의 기간이 변경됩니다. /// </summary> /// <param name="item"></param> public override void Add(ITimePeriod item) { item.ShouldNotBeNull("item"); item.AssertMutable(); ITimePeriod last = Last; if (last != null) { AssertSpaceAfter(last.End, item.Duration); item.Setup(last.End, last.End.Add(item.Duration)); } if (IsDebugEnabled) { log.Debug("Period를 Chain의 끝에 추가합니다. item=[{0}]", item); } _periods.Add(item); }
/// <summary> /// 두 기간이 겹치는 구간이 있는지 파악합니다. /// </summary> /// <param name="period"></param> /// <param name="target"></param> /// <returns></returns> public static bool OverlapsWith(this ITimePeriod period, ITimePeriod target) { target.ShouldNotBeNull("target"); var relation = GetReleation(period, target); //period.GetRelation(target); var isOverlaps = relation != PeriodRelation.After && relation != PeriodRelation.StartTouching && relation != PeriodRelation.EndTouching && relation != PeriodRelation.Before; if (IsDebugEnabled) { log.Debug("period[{0}]와 target[{1}]이 Overlap되는지 있는지 확인합니다. isOverlaps=[{2}]", period.AsString(), target.AsString(), isOverlaps); } return(isOverlaps); }
/// <summary> /// 주어진 기간이 오버랩되는지를 파악하는 Criterion /// </summary> public static ICriterion IsOverlapCriterion(this ITimePeriod period, string loPropertyName, string hiPropertyName) { period.ShouldNotBeNull("range"); Guard.Assert(period.IsAnytime == false, @"기간이 설정되어 있지 않습니다. 상하한 값 모두 없으므로, 질의어를 만들 필요가 없습니다."); loPropertyName.ShouldNotBeWhiteSpace("loProperty"); hiPropertyName.ShouldNotBeWhiteSpace("hiProperty"); if (IsDebugEnabled) { log.Debug("Build IsOverlapCriterion... range={0}, loPropertyName={1}, hiPropertyName={2}", period, loPropertyName, hiPropertyName); } if (period.HasStart && period.HasEnd) { return(Restrictions.Disjunction() .Add(period.Start.IsInRangeCriterion(loPropertyName, hiPropertyName)) .Add(period.End.IsInRangeCriterion(loPropertyName, hiPropertyName)) .Add(loPropertyName.IsBetweenCriterion(period.Start, period.End)) .Add(hiPropertyName.IsBetweenCriterion(period.Start, period.End))); } if (period.HasStart) { return(Restrictions.Disjunction() .Add(period.Start.IsInRangeCriterion(loPropertyName, hiPropertyName)) .Add(Restrictions.Ge(loPropertyName, period.Start)) .Add(Restrictions.Ge(hiPropertyName, period.Start))); } if (period.HasEnd) { return(Restrictions.Disjunction() .Add(period.End.IsInRangeCriterion(loPropertyName, hiPropertyName)) .Add(Restrictions.Le(loPropertyName, period.End)) .Add(Restrictions.Le(hiPropertyName, period.End))); } throw new InvalidOperationException("기간이 Overlap되는지 판단하는 Criterion을 생성하기 위한 조건이 맞지 않습니다."); }
/// <summary> /// 두 기간의 공통되는 기간을 반환한다. (교집합) /// </summary> /// <param name="period"></param> /// <param name="target"></param> /// <returns></returns> public static TimeRange GetIntersectionRange(this ITimePeriod period, ITimePeriod target) { target.ShouldNotBeNull("target"); TimeRange intersectionPeriod = null; if (IntersectsWith(period, target)) { var start = Max(period.Start, target.Start); var end = Min(period.End, target.End); intersectionPeriod = new TimeRange(start, end, period.IsReadOnly); } if (IsDebugEnabled) { log.Debug("period[{0}]와 target[{1}] 의 교집합 TimeRange [{2}]를 구했습니다!!!", period.AsString(), target.AsString(), intersectionPeriod.AsString()); } return(intersectionPeriod); }
/// <summary> /// 기간 단위에 따라 Category를 생성합니다. /// </summary> /// <param name="categoryCollectionList">생성된 <see cref="CategoriesElement"/> 정보가 담길 객체</param> /// <param name="timePeriod">Gantt에 표현할 전체 기간 (프로젝트 전체 기간)</param> /// <param name="periodFlags">Gantt Chart X축에 나타낼 기간 단위 정보</param> public static void GenerateCategories(IList<CategoriesElement> categoryCollectionList, ITimePeriod timePeriod, PeriodFlags periodFlags) { categoryCollectionList.ShouldNotBeNull("categoryCollectionList"); timePeriod.ShouldNotBeNull("periodRange"); Guard.Assert(timePeriod.HasPeriod, "Gantt에 나타낼 전체 기간은 시작과 끝이 있어야합니다."); if(IsDebugEnabled) log.Debug("Gantt의 기간 부분을 생성합니다. timePeriod=[{0}], periodFlags=[{1}]", timePeriod, periodFlags); categoryCollectionList.Clear(); if((periodFlags & PeriodFlags.Year) > 0) categoryCollectionList.Add(CreateCategories(timePeriod.ForEachYears(), range => range.Start.Year.ToString())); if((periodFlags & PeriodFlags.HalfYear) > 0) categoryCollectionList.Add(CreateCategories(timePeriod.ForEachYears(), range => (range.End.HalfyearOf() == HalfyearKind.First) ? "1st" : "2nd")); if((periodFlags & PeriodFlags.Quarter) > 0) categoryCollectionList.Add(CreateCategories(timePeriod.ForEachQuarters(), range => "Q" + range.End.QuarterOf().GetHashCode().ToString())); if((periodFlags & PeriodFlags.Month) > 0) categoryCollectionList.Add(CreateCategories(timePeriod.ForEachMonths(), range => range.End.GetMonthName())); if((periodFlags & PeriodFlags.Week) > 0) categoryCollectionList.Add(CreateCategories(timePeriod.ForEachWeeks(), range => "W" + range.End.GetYearAndWeek().Week.Value.ToString())); if((periodFlags & PeriodFlags.Day) > 0) categoryCollectionList.Add(CreateCategoriesAsParallel(timePeriod.ForEachDays(), range => range.End.Day.ToString())); if((periodFlags & PeriodFlags.Hour) > 0) categoryCollectionList.Add(CreateCategoriesAsParallel(timePeriod.ForEachHours(), range => "H" + range.End.Hour.ToString())); }
/// <summary> /// 두 기간의 합집합 기간을 반환한다. /// </summary> /// <param name="period"></param> /// <param name="target"></param> /// <returns></returns> public static TimeRange GetUnionRange(this ITimePeriod period, ITimePeriod target) { target.ShouldNotBeNull("target"); TimeRange unionPeriod = null; if (period.HasPeriod && target.HasPeriod) { unionPeriod = new TimeRange(period.StartAsNullable <target.StartAsNullable ?period.StartAsNullable : target.StartAsNullable, period.EndAsNullable> target.EndAsNullable ? period.EndAsNullable : target.EndAsNullable, period.IsReadOnly); } else { var start = (period.StartAsNullable.HasValue && target.StartAsNullable.HasValue) ? Min(period.Start, target.Start) : (period.StartAsNullable ?? target.StartAsNullable); var end = (period.EndAsNullable.HasValue && target.EndAsNullable.HasValue) ? Max(period.End, target.End) : (period.EndAsNullable ?? target.EndAsNullable); unionPeriod = new TimeRange(start, end, period.IsReadOnly); } if (IsDebugEnabled) { log.Debug("period[{0}]와 target[{1}] 의 합집합 TimeRange [{2}]를 구했습니다!!!", period.AsString(), target.AsString(), unionPeriod.AsString()); } return(unionPeriod); }
/// <summary> /// 두 기간의 합집합 기간을 반환한다. /// </summary> /// <param name="period"></param> /// <param name="target"></param> /// <returns></returns> public static TimeRange GetUnionRange(this ITimePeriod period, ITimePeriod target) { target.ShouldNotBeNull("target"); TimeRange unionPeriod = null; if(period.HasPeriod && target.HasPeriod) { unionPeriod = new TimeRange(period.StartAsNullable < target.StartAsNullable ? period.StartAsNullable : target.StartAsNullable, period.EndAsNullable > target.EndAsNullable ? period.EndAsNullable : target.EndAsNullable, period.IsReadOnly); } else { var start = (period.StartAsNullable.HasValue && target.StartAsNullable.HasValue) ? Min(period.Start, target.Start) : (period.StartAsNullable ?? target.StartAsNullable); var end = (period.EndAsNullable.HasValue && target.EndAsNullable.HasValue) ? Max(period.End, target.End) : (period.EndAsNullable ?? target.EndAsNullable); unionPeriod = new TimeRange(start, end, period.IsReadOnly); } if(IsDebugEnabled) log.Debug("period[{0}]와 target[{1}] 의 합집합 TimeRange [{2}]를 구했습니다!!!", period.AsString(), target.AsString(), unionPeriod.AsString()); return unionPeriod; }
/// <summary> /// 두 기간의 합집합 기간을 반환합니다. /// </summary> /// <param name="other"></param> /// <returns></returns> public new TimeBlock GetUnion(ITimePeriod other) { other.ShouldNotBeNull("other"); return TimeTool.GetUnionBlock(this, other); }
/// <summary> /// <paramref name="period"/> 기간 내에서 예외 기간등을 제외한 기간들을 HourRange 컬렉션으로 단위로 반환합니다. /// </summary> /// <param name="period"></param> /// <returns></returns> private IEnumerable<ITimePeriod> GetAvailableWeekPeriods(ITimePeriod period) { period.ShouldNotBeNull("period"); if(WeekDays.Count == 0 && WorkingHours.Count == 0 && WorkingDayHours.Count == 0) return new TimePeriodCollection { period }; // 필터에 필터링할 정보를 추가합니다. // var filter = new CalendarPeriodCollectorFilter(); WeekDays.RunEach(weekDay => filter.WeekDays.Add(weekDay)); WorkingHours.RunEach(workingHour => filter.CollectingHours.Add(workingHour)); WorkingDayHours.RunEach(workingDayHour => filter.CollectingDayHours.Add(workingDayHour)); var weekCollector = new CalendarPeriodCollector(filter, period, SeekDirection.Forward, TimeCalendar); weekCollector.CollectHours(); return weekCollector.Periods; }
/// <summary> /// <paramref name="period"/>가 <paramref name="target"/>과의 시간 축으로 선 후행 관계를 판단합니다. /// </summary> /// <param name="period"></param> /// <param name="target"></param> /// <returns></returns> public static PeriodRelation GetReleation(this ITimePeriod period, ITimePeriod target) { period.ShouldNotBeNull("period"); target.ShouldNotBeNull("target"); var relation = PeriodRelation.NoRelation; if (period.Start > target.End) { relation = PeriodRelation.After; } else if (period.End < target.Start) { relation = PeriodRelation.Before; } else if (period.Start == target.Start && period.End == target.End) { relation = PeriodRelation.ExactMatch; } else if (period.Start == target.End) { relation = PeriodRelation.StartTouching; } else if (period.End == target.Start) { relation = PeriodRelation.EndTouching; } else if (HasInside(period, target)) { if (period.Start == target.Start) { relation = PeriodRelation.EnclosingStartTouching; } else { relation = (period.End == target.End) ? PeriodRelation.EnclosingEndTouching : PeriodRelation.Enclosing; } } // 기간이 대상 기간 내부에 속할 때 else { var insideStart = HasInside(target, period.Start); var insideEnd = HasInside(target, period.End); if (insideStart && insideEnd) { relation = Equals(period.Start, target.Start) ? PeriodRelation.InsideStartTouching : period.End == target.End ? PeriodRelation.InsideEndTouching : PeriodRelation.Inside; } else if (insideStart) { relation = PeriodRelation.StartInside; } else if (insideEnd) { relation = PeriodRelation.EndInside; } } if (IsDebugEnabled) { log.Debug("period[{0}]와 target[{1}] 간의 Relation은 [{2}] 입니다.", period.AsString(), target.AsString(), relation); } return(relation); }
/// <summary> /// 기간을 지정한 기간으로 축소시킵니다. /// </summary> /// <param name="period"></param> public virtual void ShrinkTo(ITimePeriod period) { period.ShouldNotBeNull("period"); if(period.HasStart) ShrinkStartTo(period.Start); if(period.HasEnd) ShrinkEndTo(period.End); }
/// <summary> /// <see cref="ITimePeriod"/>의 Chain의 <paramref name="index"/>번째에 <paramref name="item"/>을 삽입합니다. 선행 Period와 후행 Period의 기간 값이 조정됩니다. /// </summary> /// <param name="index">추가할 위치</param> /// <param name="item">추가할 기간</param> public override void Insert(int index, ITimePeriod item) { item.ShouldNotBeNull("item"); Guard.Assert<ArgumentOutOfRangeException>(index >= 0 && index <= Count, "인덱스 범위가 잘못되었습니다. Count=[{0}], index=[{1}]", Count, index); item.AssertMutable(); if(IsDebugEnabled) log.Debug("Chain의 인덱스[{0}]에 새로운 요소[{1}]를 삽입합니다...", index, item); var itemDuration = item.Duration; ITimePeriod previousItem = null; ITimePeriod nextItem = null; if(Count > 0) { if(index > 0) { previousItem = this[index - 1]; AssertSpaceAfter(End, itemDuration); } if(index < Count - 1) { nextItem = this[index]; AssertSpaceBefore(Start, itemDuration); } } _periods.Insert(index, item); if(previousItem != null) { if(IsDebugEnabled) log.Debug("선행 Period에 기초하여 삽입한 Period와 후행 Period들의 시간을 조정합니다..."); item.Setup(previousItem.End, previousItem.End.Add(itemDuration)); for(int i = index + 1; i < Count; i++) { var startTime = this[i].Start.Add(itemDuration); this[i].Setup(startTime, startTime.Add(this[i].Duration)); } } if(nextItem != null) { if(IsDebugEnabled) log.Debug("후행 Period에 기초하여 삽입한 Period와 선행 Period들의 시간을 조정합니다..."); var nextStart = nextItem.Start.Subtract(itemDuration); item.Setup(nextStart, nextStart.Add(itemDuration)); for(var i = 0; i < index - 1; i++) { nextStart = this[i].Start.Subtract(itemDuration); this[i].Setup(nextStart, nextStart.Add(this[i].Duration)); } } }
/// <summary> /// 지정한 기간이 현 기간과 겹치는 부분이 있는지 검사합니다. /// </summary> /// <param name="other"></param> /// <returns></returns> public virtual bool OverlapsWith(ITimePeriod other) { other.ShouldNotBeNull("other"); return TimeTool.OverlapsWith(this, other); }
/// <summary> /// 두 기간의 합집합 기간을 반환합니다. /// </summary> /// <param name="other"></param> /// <returns></returns> public virtual TimePeriodBase GetUnion(ITimePeriod other) { other.ShouldNotBeNull("other"); return TimeTool.GetUnionRange(this, other); }
/// <summary> /// 두 기간이 같은 기간을 나타내는지 검사합니다 /// </summary> /// <param name="other">비교할 대상</param> /// <returns></returns> public virtual bool IsSamePeriod(ITimePeriod other) { other.ShouldNotBeNull("other"); return Equals(Start, other.Start) && Equals(End, other.End); }
/// <summary> /// 지정한 기간이 현 기간 내에 속하는지 검사합니다. /// </summary> /// <param name="other"></param> /// <returns></returns> public virtual bool HasInside(ITimePeriod other) { other.ShouldNotBeNull("other"); return TimeTool.HasInside(this, other); }
/// <summary> /// 새로운 <paramref name="item"/>을 Chain의 제일 끝에 붙여 넣습니다. <paramref name="item"/>의 기간이 변경됩니다. /// </summary> /// <param name="item"></param> public override void Add(ITimePeriod item) { item.ShouldNotBeNull("item"); item.AssertMutable(); ITimePeriod last = Last; if(last != null) { AssertSpaceAfter(last.End, item.Duration); item.Setup(last.End, last.End.Add(item.Duration)); } if(IsDebugEnabled) log.Debug("Period를 Chain의 끝에 추가합니다. item=[{0}]", item); _periods.Add(item); }
/// <summary> /// 두 기간의 합집합 기간을 반환합니다. /// </summary> /// <param name="other"></param> /// <returns></returns> public new ITimeInterval GetUnion(ITimePeriod other) { other.ShouldNotBeNull("other"); return (TimeInterval)TimeTool.GetUnionRange(this, other); }
/// <summary> /// 두 기간의 공통되는 기간을 반환한다. (교집합) /// </summary> /// <param name="period"></param> /// <param name="target"></param> /// <returns></returns> public static TimeRange GetIntersectionRange(this ITimePeriod period, ITimePeriod target) { target.ShouldNotBeNull("target"); TimeRange intersectionPeriod = null; if(IntersectsWith(period, target)) { var start = Max(period.Start, target.Start); var end = Min(period.End, target.End); intersectionPeriod = new TimeRange(start, end, period.IsReadOnly); } if(IsDebugEnabled) log.Debug("period[{0}]와 target[{1}] 의 교집합 TimeRange [{2}]를 구했습니다!!!", period.AsString(), target.AsString(), intersectionPeriod.AsString()); return intersectionPeriod; }
/// <summary> /// 두 기간의 합집합 기간을 반환합니다. /// </summary> /// <param name="other"></param> /// <returns></returns> public virtual TimePeriodBase GetUnion(ITimePeriod other) { other.ShouldNotBeNull("other"); return(TimeTool.GetUnionRange(this, other)); }
/// <summary> /// 시작시각과 완료시각을 지정된 기간 정보를 기준으로 변경합니다. /// </summary> /// <param name="period"></param> public void ExpandTo(ITimePeriod period) { period.ShouldNotBeNull("period"); AssertMutable(); if(period.HasStart) ExpandStartTo(period.Start); if(period.HasEnd) ExpandEndTo(period.End); }
/// <summary> /// <paramref name="item"/>을 <paramref name="index"/> 순서에 삽입합니다. /// </summary> /// <param name="index"></param> /// <param name="item"></param> public virtual void Insert(int index, ITimePeriod item) { item.ShouldNotBeNull("item"); _periods.Insert(index, item); }
/// <summary> /// 두 기간의 합집합 기간을 반환합니다. /// </summary> /// <param name="other"></param> /// <returns></returns> public new ITimeRange GetUnion(ITimePeriod other) { other.ShouldNotBeNull("other"); return TimeTool.GetUnionRange(this, other); }
/// <summary> /// 두 기간의 겹치는 기간을 반환합니다. /// </summary> /// <param name="other"></param> /// <returns></returns> public new ITimeRange GetIntersection(ITimePeriod other) { other.ShouldNotBeNull("other"); return(TimeTool.GetIntersectionRange(this, other)); }
/// <summary> /// TimePeriodChain에서 요소 <paramref name="item"/>을 제거합니다. (제거된 후의 후속 Period들의 시간이 조정됩니다) /// </summary> /// <param name="item"></param> /// <returns></returns> public override bool Remove(ITimePeriod item) { item.ShouldNotBeNull("item"); if(Count <= 0) return false; if(IsDebugEnabled) log.Debug("요소[{0}] 를 제거하려고 합니다...", item); var itemDuration = item.Duration; var index = IndexOf(item); ITimePeriod next = null; if(itemDuration > TimeSpan.Zero && index > 0 && index < Count - 1) next = this[index]; var removed = _periods.Remove(item); if(removed && next != null) { if(IsDebugEnabled) log.Debug("요소[{0}]를 제거하고, Chain의 후속 Period 들의 기간을 조정합니다...", item); for(int i = index; i < Count; i++) { var start = this[i].Start.Subtract(itemDuration); this[i].Setup(start, start.Add(this[i].Duration)); } } if(IsDebugEnabled) log.Debug("요소[{0}] 를 제거 결과=[{1}]", item, removed); return removed; }
/// <summary> /// 두 기간의 합집합 기간을 반환합니다. /// </summary> /// <param name="other"></param> /// <returns></returns> public new ITimeInterval GetUnion(ITimePeriod other) { other.ShouldNotBeNull("other"); return((TimeInterval)TimeTool.GetUnionRange(this, other)); }
/// <summary> /// 대상 기간을 포함하고 있는지 검사합니다. /// </summary> /// <param name="target"></param> /// <returns></returns> public virtual bool ContainsPeriod(ITimePeriod target) { target.ShouldNotBeNull("target"); return _periods.Any(p => p.IsSamePeriod(target)); }
/// <summary> /// 두 기간이 겹치는 구간이 있는지 파악합니다. /// </summary> /// <param name="period"></param> /// <param name="target"></param> /// <returns></returns> public static bool OverlapsWith(this ITimePeriod period, ITimePeriod target) { target.ShouldNotBeNull("target"); var relation = GetReleation(period, target); //period.GetRelation(target); var isOverlaps = relation != PeriodRelation.After && relation != PeriodRelation.StartTouching && relation != PeriodRelation.EndTouching && relation != PeriodRelation.Before; if(IsDebugEnabled) log.Debug("period[{0}]와 target[{1}]이 Overlap되는지 있는지 확인합니다. isOverlaps=[{2}]", period.AsString(), target.AsString(), isOverlaps); return isOverlaps; }
/// <summary> /// 두 기간의 합집합 기간을 반환합니다. /// </summary> /// <param name="other"></param> /// <returns></returns> public new TimeBlock GetUnion(ITimePeriod other) { other.ShouldNotBeNull("other"); return(TimeTool.GetUnionBlock(this, other)); }
/// <summary> /// 지정한 기간이 현 기간과 겹치는 부분이 있는지 검사합니다. /// </summary> /// <param name="other"></param> /// <returns></returns> public virtual bool IntersectsWith(ITimePeriod other) { other.ShouldNotBeNull("other"); return TimeTool.IntersectsWith(this, other); }
/// <summary> /// 대상 기간을 포함하고 있는지 검사합니다. /// </summary> /// <param name="target"></param> /// <returns></returns> public virtual bool ContainsPeriod(ITimePeriod target) { target.ShouldNotBeNull("target"); return(_periods.Any(p => p.IsSamePeriod(target))); }
/// <summary> /// 다른 TimePeriod와의 관계를 나타냅니다. /// </summary> /// <param name="other"></param> /// <returns></returns> public virtual PeriodRelation GetRelation(ITimePeriod other) { other.ShouldNotBeNull("other"); return TimeTool.GetReleation(this, other); }
/// <summary> /// 두 기간이 같은 기간을 나타내는지 검사합니다 /// </summary> /// <param name="other">비교할 대상</param> /// <returns></returns> public virtual bool IsSamePeriod(ITimePeriod other) { other.ShouldNotBeNull("other"); return(Equals(Start, other.Start) && Equals(End, other.End)); }
protected void StartPeriodVisit(ITimePeriod period, TContext context) { if (IsDebugEnabled) { log.Debug("기간에 대한 탐색을 시작합니다... period=[{0}], context=[{1}]", period, context); } period.ShouldNotBeNull("period"); if (period.IsMoment) { return; } OnVisitStart(); var years = (Calendar != null) ? new YearRangeCollection(period.Start.Year, period.End.Year - period.Start.Year + 1, Calendar) : new YearRangeCollection(period.Start.Year, period.End.Year - period.Start.Year + 1); if (OnVisitYears(years, context) && EnterYears(years, context)) { var yearsToVisit = years.GetYears().ToTimePeriodCollection(); if (SeekDirection == SeekDirection.Backward) { yearsToVisit.SortByEnd(OrderDirection.Asc); } foreach (YearRange year in yearsToVisit) { //if(IsDebugEnabled) // log.Debug("Year[{0}]를 탐색합니다...", year.YearValue); if (year.OverlapsWith(period) == false || OnVisitYear(year, context) == false) { continue; } if (EnterMonths(year, context) == false) { continue; } var monthsToVisit = year.GetMonths().ToTimePeriodCollection(); if (SeekDirection == SeekDirection.Backward) { monthsToVisit.SortByEnd(OrderDirection.Asc); } monthsToVisit .Cast <MonthRange>() #if !SILVERLIGHT .AsParallel() .AsOrdered() #endif .RunEach(month => // foreach(MonthRange month in monthsToVisit) { //if(IsDebugEnabled) // log.Debug("Month[{0}]를 탐색합니다...", month.Month); if (month.OverlapsWith(period) == false || OnVisitMonth(month, context) == false) { return; } if (EnterDays(month, context) == false) { return; } var daysToVisit = month.GetDays().ToTimePeriodCollection(); if (SeekDirection == SeekDirection.Backward) { daysToVisit.SortByEnd(OrderDirection.Asc); } foreach (DayRange day in daysToVisit) { //if(IsDebugEnabled) // log.Debug("Day[{0}]를 탐색합니다...", day.Day); if (day.OverlapsWith(period) == false || OnVisitDay(day, context) == false) { continue; } if (EnterHours(day, context) == false) { continue; } var hoursToVisit = day.GetHours().ToTimePeriodCollection(); if (SeekDirection == SeekDirection.Backward) { hoursToVisit.SortByEnd(OrderDirection.Asc); } foreach (HourRange hour in hoursToVisit) { //if(IsDebugEnabled) // log.Debug("Hour[{0}]를 탐색합니다...", hour.Hour); if (hour.OverlapsWith(period) == false || OnVisitHour(hour, context) == false) { continue; } //if(EnterMinutes(hour, context) == false) // continue; //var minutesToVisit = hour.GetMinutes(); //if(SeekDirection == SeekDirection.Backward) // minutesToVisit.SortByEnd(null); //foreach(MinuteRange minute in minutesToVisit) //{ // if(minute.OverlapsWith(period) == false || OnVisitMinute(minute, context) == false) // continue; //} } } }); } } OnVisitEnd(); if (IsDebugEnabled) { log.Debug("기간에 대한 탐색을 완료했습니다!!! period=[{0}], context=[{1}]", period, context); } }
/// <summary> /// 두 기간 교차하거나, <paramref name="period"/>가 <paramref name="target"/> 의 내부 구간이면 true를 반환합니다. /// </summary> /// <param name="period"></param> /// <param name="target"></param> /// <returns></returns> public static bool IntersectsWith(this ITimePeriod period, ITimePeriod target) { target.ShouldNotBeNull("target"); var isIntersected = period.HasInside(target.Start) || period.HasInside(target.End) || (target.Start < period.Start && target.End > period.End); if(IsDebugEnabled) log.Debug("period[{0}]와 target[{1}]이 교차 구간이 있는지 확인합니다. isIntersected=[{2}]", period.AsString(), target.AsString(), isIntersected); return isIntersected; }