/* * Copyright 2011-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package kr.debop4j.timeperiod.calendars; import kr.debop4j.timeperiod.*; import kr.debop4j.timeperiod.timeline.TimeGapCalculator; import kr.debop4j.timeperiod.tools.TimeSpec; import kr.debop4j.timeperiod.tools.Times; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.joda.time.DateTime; import org.joda.time.Duration; import java.util.Collections; import java.util.List; import java.util.Objects; import static kr.debop4j.core.Guard.shouldBe; import static kr.debop4j.core.Guard.shouldNotBeNull; import static kr.debop4j.timeperiod.tools.Durations.Zero; import static kr.debop4j.timeperiod.tools.Durations.negate; import static kr.debop4j.timeperiod.tools.Times.startTimeOfDay; import static org.joda.time.Duration.ZERO; /** * 특정 {@link ITimeCalendar} 기준으로 특정 일자간의 기간({@link org.joda.time.Duration} 을 구합니다. * * @author 배성혁 sunghyouk.bae@gmail.com * @since 13. 5. 21. 오전 9:29 */ @Slf4j public class CalendarDateDiff { private final CalendarPeriodCollectorFilter collectorFilter = new CalendarPeriodCollectorFilter(); @Getter private final ITimeCalendar calendar; public CalendarDateDiff() { this(TimeCalendar.getEmptyOffset()); } public CalendarDateDiff(ITimeCalendar calendar) { shouldNotBeNull(calendar, "calendar"); shouldBe(calendar.getStartOffset().isEqual(ZERO), "Calendar.StartOffset은 Duration.ZERO 이어야 합니다."); shouldBe(calendar.getEndOffset().isEqual(ZERO), "Calendar.EndOffset은 Duration.ZERO 이어야 합니다."); this.calendar = calendar; } public List<DayOfWeek> getWeekDays() { return collectorFilter.getWeekDays(); } public List<HourRangeInDay> getWorkingHours() { return this.collectorFilter.getCollectingHours(); } public List<DayHourRange> getWorkingDayHours() { return this.collectorFilter.getCollectingDayHours(); } /** 주중 (월-금)을 working day로 추가합니다. */ public void addWorkingDays() { addWeekDays(TimeSpec.Weekdays); } /** 주말 (토-일)을 working day로 추가합니다. */ public void addWeekendDays() { addWeekDays(TimeSpec.Weekends); } private void addWeekDays(DayOfWeek... dayOfWeeks) { if (getWeekDays() != null) Collections.addAll(getWeekDays(), dayOfWeeks); } /** * 지정된 시각부터 현재 시각까지의 기간을 계산합니다. * * @param moment 시작 시각 * @return 시작 시각 ~ 완료 시각 사이의 Working Hours */ public Duration difference(DateTime moment) { return difference(moment, Times.now()); } /** * 시작 시각 ~ 완료 시각 사이의 기간의 Working Time을 계산합니다. * * @param fromTime 시작 시각 * @param toTime 완료 시각 * @return 시작 시각 ~ 완료 시각 사이의 Working Hours */ public Duration difference(DateTime fromTime, DateTime toTime) { if (CalendarDateDiff.log.isTraceEnabled()) CalendarDateDiff.log.trace("fromTime[{}] ~ toTime[{}]의 Working Time을 구합니다.", fromTime, toTime); if (Objects.equals(fromTime, toTime)) return Zero; boolean filterIsEmpty = this.getWeekDays().size() == 0 && this.getWorkingHours().size() == 0 && this.getWorkingDayHours().size() == 0; if (filterIsEmpty) { return new DateDiff(fromTime, toTime, getCalendar()).getDifference(); } TimeRange differenceRange = new TimeRange(fromTime, toTime); CalendarPeriodCollector collector = new CalendarPeriodCollector(this.collectorFilter, new TimeRange(startTimeOfDay(differenceRange.getStart()), startTimeOfDay(differenceRange.getEnd()).plusDays(1)), SeekDirection.Forward, getCalendar()); // Gap을 계산합니다. TimeGapCalculator<TimeRange> gapCalculator = new TimeGapCalculator<>(getCalendar()); ITimePeriodCollection gaps = gapCalculator.getGaps(collector.getPeriods(), differenceRange); Duration difference = Zero; for (ITimePeriod gap : gaps) { difference.plus(gap.getDuration()); } if (CalendarDateDiff.log.isTraceEnabled()) CalendarDateDiff.log.trace("fromTime[{}] ~ toTime[{}]의 Working Time을 구했습니다. differece=[{}]", fromTime, toTime, difference); return (fromTime.compareTo(toTime) <= 0) ? difference : negate(difference); } }