001/*
002 * ObjectLab, http://www.objectlab.co.uk/open is sponsoring the ObjectLab Kit.
003 *
004 * Based in London, we are world leaders in the design and development
005 * of bespoke applications for the securities financing markets.
006 *
007 * <a href="http://www.objectlab.co.uk/open">Click here to learn more</a>
008 *           ___  _     _           _   _          _
009 *          / _ \| |__ (_) ___  ___| |_| |    __ _| |__
010 *         | | | | '_ \| |/ _ \/ __| __| |   / _` | '_ \
011 *         | |_| | |_) | |  __/ (__| |_| |__| (_| | |_) |
012 *          \___/|_.__// |\___|\___|\__|_____\__,_|_.__/
013 *                   |__/
014 *
015 *                     www.ObjectLab.co.uk
016 *
017 * $Id$
018 *
019 * Copyright 2006 the original author or authors.
020 *
021 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
022 * use this file except in compliance with the License. You may obtain a copy of
023 * the License at
024 *
025 * http://www.apache.org/licenses/LICENSE-2.0
026 *
027 * Unless required by applicable law or agreed to in writing, software
028 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
029 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
030 * License for the specific language governing permissions and limitations under
031 * the License.
032 */
033package net.objectlab.kit.datecalc.jdk8;
034
035import java.time.LocalDate;
036import java.util.Collections;
037
038import net.objectlab.kit.datecalc.common.AbstractDateCalculator;
039import net.objectlab.kit.datecalc.common.DateCalculator;
040import net.objectlab.kit.datecalc.common.DefaultHolidayCalendar;
041import net.objectlab.kit.datecalc.common.HolidayCalendar;
042import net.objectlab.kit.datecalc.common.HolidayHandler;
043import net.objectlab.kit.datecalc.common.WorkingWeek;
044
045/**
046 * This class is used via the DateCalculator interface, it enables the handling
047 * of different HolidayHandler, if no HolidayHandler is defined, the calendar
048 * will NOT move a date, even if it falls on a holiday or weekend.
049 *
050 * @author Benoit Xhenseval
051 *
052 */
053public class LocalDateCalculator extends AbstractDateCalculator<LocalDate> {
054
055    private Jdk8WorkingWeek workingWeek = Jdk8WorkingWeek.DEFAULT;
056
057    public LocalDateCalculator() {
058        this(null, null, new DefaultHolidayCalendar<>(Collections.emptySet()), null);
059    }
060
061    public LocalDateCalculator(final String name, final LocalDate startDate, final HolidayCalendar<LocalDate> holidayCalendar,
062            final HolidayHandler<LocalDate> holidayHandler) {
063        super(name, holidayCalendar, holidayHandler);
064        if (startDate != null) {
065            setStartDate(startDate);
066        }
067    }
068
069    /**
070     * Set the working week.
071     * @param week the JodaWorkingWeek
072     * @throws IllegalArgumentException if the week is not a JodaWorkingWeek.
073     */
074    @Override
075    public DateCalculator<LocalDate> setWorkingWeek(final WorkingWeek week) {
076        if (week instanceof Jdk8WorkingWeek) {
077            workingWeek = (Jdk8WorkingWeek) week;
078            return this;
079        }
080        throw new IllegalArgumentException("Please give an instance of JodaWorkingWeek");
081    }
082
083    /**
084     * is the date a non-working day according to the WorkingWeek?
085     */
086    @Override
087    public boolean isWeekend(final LocalDate date) {
088        assert workingWeek != null;
089        return !workingWeek.isWorkingDay(date);
090    }
091
092    // -----------------------------------------------------------------------
093    //
094    // ObjectLab, world leaders in the design and development of bespoke
095    // applications for the securities financing markets.
096    // www.ObjectLab.co.uk
097    //
098    // -----------------------------------------------------------------------
099
100    @Override
101    public DateCalculator<LocalDate> moveByDays(final int days) {
102        setCurrentIncrement(days);
103
104        setCurrentBusinessDate(getCurrentBusinessDate().plusDays(days));
105
106        if (getHolidayHandler() != null) {
107            setCurrentBusinessDate(getHolidayHandler().moveCurrentDate(this));
108        }
109
110        return this;
111    }
112
113    @Override
114    public DateCalculator<LocalDate> moveByMonths(final int months) {
115        setCurrentIncrement(months);
116
117        setCurrentBusinessDate(getCurrentBusinessDate().plusMonths(months));
118
119        if (getHolidayHandler() != null) {
120            setCurrentBusinessDate(getHolidayHandler().moveCurrentDate(this));
121        }
122
123        return this;
124    }
125
126    @Override
127    protected DateCalculator<LocalDate> createNewCalculator(final String name, final LocalDate startDate, final HolidayCalendar<LocalDate> holidays,
128            final HolidayHandler<LocalDate> handler) {
129        return new LocalDateCalculator(name, startDate, holidays, handler);
130    }
131
132    @Override
133    protected LocalDate getToday() {
134        return LocalDate.now();
135    }
136
137    @Override
138    protected LocalDate compareDate(final LocalDate date1, final LocalDate date2, final boolean returnEarliest) {
139        if (date1 == null || date2 == null) {
140            return null;
141        }
142        if (returnEarliest) {
143            return date1.isAfter(date2) ? date2 : date1;
144        } else {
145            return date2.isAfter(date1) ? date2 : date1;
146        }
147    }
148
149    @Override
150    protected void checkBoundary(final LocalDate date) {
151        final LocalDate early = getHolidayCalendar().getEarlyBoundary();
152        if (early != null && early.isAfter(date)) {
153            throw new IndexOutOfBoundsException(date + " is before the early boundary " + early);
154        }
155
156        final LocalDate late = getHolidayCalendar().getLateBoundary();
157        if (late != null && late.isBefore(date)) {
158            throw new IndexOutOfBoundsException(date + " is after the late boundary " + late);
159        }
160    }
161
162    @Override
163    protected LocalDate clone(final LocalDate date) {
164        return date;
165    }
166
167    @Override
168    public int getNumberOfBusinessDaysBetween(final LocalDate d1, final LocalDate d2) {
169        if (d1 == null || d2 == null) {
170            return 0;
171        }
172        final boolean d1B4d2 = !d1.isAfter(d2);
173        LocalDate start = d1B4d2 ? d1 : d2;
174        LocalDate end = d1B4d2 ? d2 : d1;
175        if (getHolidayHandler() != null) {
176            start = getHolidayHandler().adjustDate(start, 1, this);
177        }
178
179        int count = 0;
180        while (start.isBefore(end)) {
181            if (!isNonWorkingDay(start)) {
182                count++;
183            }
184            start = start.plusDays(1);
185        }
186        return d1B4d2 ? count : -count;
187    }
188}
189
190/*
191 * ObjectLab, http://www.objectlab.co.uk/open is sponsoring the ObjectLab Kit.
192 *
193 * Based in London, we are world leaders in the design and development
194 * of bespoke applications for the securities financing markets.
195 *
196 * <a href="http://www.objectlab.co.uk/open">Click here to learn more about us</a>
197 *           ___  _     _           _   _          _
198 *          / _ \| |__ (_) ___  ___| |_| |    __ _| |__
199 *         | | | | '_ \| |/ _ \/ __| __| |   / _` | '_ \
200 *         | |_| | |_) | |  __/ (__| |_| |__| (_| | |_) |
201 *          \___/|_.__// |\___|\___|\__|_____\__,_|_.__/
202 *                   |__/
203 *
204 *                     www.ObjectLab.co.uk
205 */