001/*
002 * Copyright (c) 2007-2013, Stephen Colebourne & Michael Nascimento Santos
003 *
004 * All rights reserved.
005 *
006 * Redistribution and use in source and binary forms, with or without
007 * modification, are permitted provided that the following conditions are met:
008 *
009 *  * Redistributions of source code must retain the above copyright notice,
010 *    this list of conditions and the following disclaimer.
011 *
012 *  * Redistributions in binary form must reproduce the above copyright notice,
013 *    this list of conditions and the following disclaimer in the documentation
014 *    and/or other materials provided with the distribution.
015 *
016 *  * Neither the name of JSR-310 nor the names of its contributors
017 *    may be used to endorse or promote products derived from this software
018 *    without specific prior written permission.
019 *
020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
021 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
022 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
023 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
024 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
027 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
028 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
029 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
030 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031 */
032package org.threeten.bp.temporal;
033
034import static org.threeten.bp.temporal.ChronoField.DAY_OF_MONTH;
035import static org.threeten.bp.temporal.ChronoField.DAY_OF_WEEK;
036import static org.threeten.bp.temporal.ChronoField.DAY_OF_YEAR;
037import static org.threeten.bp.temporal.ChronoUnit.DAYS;
038import static org.threeten.bp.temporal.ChronoUnit.MONTHS;
039import static org.threeten.bp.temporal.ChronoUnit.YEARS;
040
041import java.util.Objects;
042
043import org.threeten.bp.DayOfWeek;
044
045/**
046 * Common implementations of {@code TemporalAdjuster}.
047 * <p>
048 * This class provides common implementations of {@link TemporalAdjuster}.
049 * They are especially useful to document the intent of business logic and
050 * often link well to requirements.
051 * For example, these two pieces of code do the same thing, but the second
052 * one is clearer (assuming that there is a static import of this class):
053 * <pre>
054 *  // direct manipulation
055 *  date.withDayOfMonth(1).plusMonths(1).minusDays(1);
056 *  // use of an adjuster from this class
057 *  date.with(lastDayOfMonth());
058 * </pre>
059 * There are two equivalent ways of using a {@code TemporalAdjuster}.
060 * The first is to invoke the method on the interface directly.
061 * The second is to use {@link Temporal#with(TemporalAdjuster)}:
062 * <pre>
063 *   // these two lines are equivalent, but the second approach is recommended
064 *   dateTime = adjuster.adjustInto(dateTime);
065 *   dateTime = dateTime.with(adjuster);
066 * </pre>
067 * It is recommended to use the second approach, {@code with(TemporalAdjuster)},
068 * as it is a lot clearer to read in code.
069 *
070 * <h3>Specification for implementors</h3>
071 * This is a thread-safe utility class.
072 * All returned adjusters are immutable and thread-safe.
073 */
074public final class TemporalAdjusters {
075
076    /**
077     * Private constructor since this is a utility class.
078     */
079    private TemporalAdjusters() {
080    }
081
082    //-----------------------------------------------------------------------
083    /**
084     * Returns the "first day of month" adjuster, which returns a new date set to
085     * the first day of the current month.
086     * <p>
087     * The ISO calendar system behaves as follows:<br>
088     * The input 2011-01-15 will return 2011-01-01.<br>
089     * The input 2011-02-15 will return 2011-02-01.
090     * <p>
091     * The behavior is suitable for use with most calendar systems.
092     * It is equivalent to:
093     * <pre>
094     *  temporal.with(DAY_OF_MONTH, 1);
095     * </pre>
096     *
097     * @return the first day-of-month adjuster, not null
098     */
099    public static TemporalAdjuster firstDayOfMonth() {
100        return Impl.FIRST_DAY_OF_MONTH;
101    }
102
103    /**
104     * Returns the "last day of month" adjuster, which returns a new date set to
105     * the last day of the current month.
106     * <p>
107     * The ISO calendar system behaves as follows:<br>
108     * The input 2011-01-15 will return 2011-01-31.<br>
109     * The input 2011-02-15 will return 2011-02-28.<br>
110     * The input 2012-02-15 will return 2012-02-29 (leap year).<br>
111     * The input 2011-04-15 will return 2011-04-30.
112     * <p>
113     * The behavior is suitable for use with most calendar systems.
114     * It is equivalent to:
115     * <pre>
116     *  long lastDay = temporal.range(DAY_OF_MONTH).getMaximum();
117     *  temporal.with(DAY_OF_MONTH, lastDay);
118     * </pre>
119     *
120     * @return the last day-of-month adjuster, not null
121     */
122    public static TemporalAdjuster lastDayOfMonth() {
123        return Impl.LAST_DAY_OF_MONTH;
124    }
125
126    /**
127     * Returns the "first day of next month" adjuster, which returns a new date set to
128     * the first day of the next month.
129     * <p>
130     * The ISO calendar system behaves as follows:<br>
131     * The input 2011-01-15 will return 2011-02-01.<br>
132     * The input 2011-02-15 will return 2011-03-01.
133     * <p>
134     * The behavior is suitable for use with most calendar systems.
135     * It is equivalent to:
136     * <pre>
137     *  temporal.with(DAY_OF_MONTH, 1).plus(1, MONTHS);
138     * </pre>
139     *
140     * @return the first day of next month adjuster, not null
141     */
142    public static TemporalAdjuster firstDayOfNextMonth() {
143        return Impl.FIRST_DAY_OF_NEXT_MONTH;
144    }
145
146    //-----------------------------------------------------------------------
147    /**
148     * Returns the "first day of year" adjuster, which returns a new date set to
149     * the first day of the current year.
150     * <p>
151     * The ISO calendar system behaves as follows:<br>
152     * The input 2011-01-15 will return 2011-01-01.<br>
153     * The input 2011-02-15 will return 2011-01-01.<br>
154     * <p>
155     * The behavior is suitable for use with most calendar systems.
156     * It is equivalent to:
157     * <pre>
158     *  temporal.with(DAY_OF_YEAR, 1);
159     * </pre>
160     *
161     * @return the first day-of-year adjuster, not null
162     */
163    public static TemporalAdjuster firstDayOfYear() {
164        return Impl.FIRST_DAY_OF_YEAR;
165    }
166
167    /**
168     * Returns the "last day of year" adjuster, which returns a new date set to
169     * the last day of the current year.
170     * <p>
171     * The ISO calendar system behaves as follows:<br>
172     * The input 2011-01-15 will return 2011-12-31.<br>
173     * The input 2011-02-15 will return 2011-12-31.<br>
174     * <p>
175     * The behavior is suitable for use with most calendar systems.
176     * It is equivalent to:
177     * <pre>
178     *  long lastDay = temporal.range(DAY_OF_YEAR).getMaximum();
179     *  temporal.with(DAY_OF_YEAR, lastDay);
180     * </pre>
181     *
182     * @return the last day-of-year adjuster, not null
183     */
184    public static TemporalAdjuster lastDayOfYear() {
185        return Impl.LAST_DAY_OF_YEAR;
186    }
187
188    /**
189     * Returns the "first day of next year" adjuster, which returns a new date set to
190     * the first day of the next year.
191     * <p>
192     * The ISO calendar system behaves as follows:<br>
193     * The input 2011-01-15 will return 2012-01-01.
194     * <p>
195     * The behavior is suitable for use with most calendar systems.
196     * It is equivalent to:
197     * <pre>
198     *  temporal.with(DAY_OF_YEAR, 1).plus(1, YEARS);
199     * </pre>
200     *
201     * @return the first day of next month adjuster, not null
202     */
203    public static TemporalAdjuster firstDayOfNextYear() {
204        return Impl.FIRST_DAY_OF_NEXT_YEAR;
205    }
206
207    //-----------------------------------------------------------------------
208    /**
209     * Enum implementing the adjusters.
210     */
211    private static class Impl implements TemporalAdjuster {
212        /** First day of month adjuster. */
213        private static final Impl FIRST_DAY_OF_MONTH = new Impl(0);
214        /** Last day of month adjuster. */
215        private static final Impl LAST_DAY_OF_MONTH = new Impl(1);
216        /** First day of next month adjuster. */
217        private static final Impl FIRST_DAY_OF_NEXT_MONTH = new Impl(2);
218        /** First day of year adjuster. */
219        private static final Impl FIRST_DAY_OF_YEAR = new Impl(3);
220        /** Last day of year adjuster. */
221        private static final Impl LAST_DAY_OF_YEAR = new Impl(4);
222        /** First day of next month adjuster. */
223        private static final Impl FIRST_DAY_OF_NEXT_YEAR = new Impl(5);
224        /** The ordinal. */
225        private final int ordinal;
226        private Impl(int ordinal) {
227            this.ordinal = ordinal;
228        }
229        @Override
230        public Temporal adjustInto(Temporal temporal) {
231            switch (ordinal) {
232                case 0: return temporal.with(DAY_OF_MONTH, 1);
233                case 1: return temporal.with(DAY_OF_MONTH, temporal.range(DAY_OF_MONTH).getMaximum());
234                case 2: return temporal.with(DAY_OF_MONTH, 1).plus(1, MONTHS);
235                case 3: return temporal.with(DAY_OF_YEAR, 1);
236                case 4: return temporal.with(DAY_OF_YEAR, temporal.range(DAY_OF_YEAR).getMaximum());
237                case 5: return temporal.with(DAY_OF_YEAR, 1).plus(1, YEARS);
238            }
239            throw new IllegalStateException("Unreachable");
240        }
241    }
242
243    //-----------------------------------------------------------------------
244    /**
245     * Returns the first in month adjuster, which returns a new date
246     * in the same month with the first matching day-of-week.
247     * This is used for expressions like 'first Tuesday in March'.
248     * <p>
249     * The ISO calendar system behaves as follows:<br>
250     * The input 2011-12-15 for (MONDAY) will return 2011-12-05.<br>
251     * The input 2011-12-15 for (FRIDAY) will return 2011-12-02.<br>
252     * <p>
253     * The behavior is suitable for use with most calendar systems.
254     * It uses the {@code DAY_OF_WEEK} and {@code DAY_OF_MONTH} fields
255     * and the {@code DAYS} unit, and assumes a seven day week.
256     *
257     * @param dayOfWeek  the day-of-week, not null
258     * @return the first in month adjuster, not null
259     */
260    public static TemporalAdjuster firstInMonth(DayOfWeek dayOfWeek) {
261        Objects.requireNonNull(dayOfWeek, "dayOfWeek");
262        return new DayOfWeekInMonth(1, dayOfWeek);
263    }
264
265    /**
266     * Returns the last in month adjuster, which returns a new date
267     * in the same month with the last matching day-of-week.
268     * This is used for expressions like 'last Tuesday in March'.
269     * <p>
270     * The ISO calendar system behaves as follows:<br>
271     * The input 2011-12-15 for (MONDAY) will return 2011-12-26.<br>
272     * The input 2011-12-15 for (FRIDAY) will return 2011-12-30.<br>
273     * <p>
274     * The behavior is suitable for use with most calendar systems.
275     * It uses the {@code DAY_OF_WEEK} and {@code DAY_OF_MONTH} fields
276     * and the {@code DAYS} unit, and assumes a seven day week.
277     *
278     * @param dayOfWeek  the day-of-week, not null
279     * @return the first in month adjuster, not null
280     */
281    public static TemporalAdjuster lastInMonth(DayOfWeek dayOfWeek) {
282        Objects.requireNonNull(dayOfWeek, "dayOfWeek");
283        return new DayOfWeekInMonth(-1, dayOfWeek);
284    }
285
286    /**
287     * Returns the day-of-week in month adjuster, which returns a new date
288     * in the same month with the ordinal day-of-week.
289     * This is used for expressions like the 'second Tuesday in March'.
290     * <p>
291     * The ISO calendar system behaves as follows:<br>
292     * The input 2011-12-15 for (1,TUESDAY) will return 2011-12-06.<br>
293     * The input 2011-12-15 for (2,TUESDAY) will return 2011-12-13.<br>
294     * The input 2011-12-15 for (3,TUESDAY) will return 2011-12-20.<br>
295     * The input 2011-12-15 for (4,TUESDAY) will return 2011-12-27.<br>
296     * The input 2011-12-15 for (5,TUESDAY) will return 2012-01-03.<br>
297     * The input 2011-12-15 for (-1,TUESDAY) will return 2011-12-27 (last in month).<br>
298     * The input 2011-12-15 for (-4,TUESDAY) will return 2011-12-06 (3 weeks before last in month).<br>
299     * The input 2011-12-15 for (-5,TUESDAY) will return 2011-11-29 (4 weeks before last in month).<br>
300     * The input 2011-12-15 for (0,TUESDAY) will return 2011-11-29 (last in previous month).<br>
301     * <p>
302     * For a positive or zero ordinal, the algorithm is equivalent to finding the first
303     * day-of-week that matches within the month and then adding a number of weeks to it.
304     * For a negative ordinal, the algorithm is equivalent to finding the last
305     * day-of-week that matches within the month and then subtracting a number of weeks to it.
306     * The ordinal number of weeks is not validated and is interpreted leniently
307     * according to this algorithm. This definition means that an ordinal of zero finds
308     * the last matching day-of-week in the previous month.
309     * <p>
310     * The behavior is suitable for use with most calendar systems.
311     * It uses the {@code DAY_OF_WEEK} and {@code DAY_OF_MONTH} fields
312     * and the {@code DAYS} unit, and assumes a seven day week.
313     *
314     * @param ordinal  the week within the month, unbound but typically from -5 to 5
315     * @param dayOfWeek  the day-of-week, not null
316     * @return the day-of-week in month adjuster, not null
317     * @throws IllegalArgumentException if the ordinal is invalid
318     */
319    public static TemporalAdjuster dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek) {
320        Objects.requireNonNull(dayOfWeek, "dayOfWeek");
321        return new DayOfWeekInMonth(ordinal, dayOfWeek);
322    }
323
324    /**
325     * Class implementing day-of-week in month adjuster.
326     */
327    private static final class DayOfWeekInMonth implements TemporalAdjuster {
328        /** The ordinal. */
329        private final int ordinal;
330        /** The day-of-week value, from 1 to 7. */
331        private final int dowValue;
332
333        private DayOfWeekInMonth(int ordinal, DayOfWeek dow) {
334            super();
335            this.ordinal = ordinal;
336            this.dowValue = dow.getValue();
337        }
338        @Override
339        public Temporal adjustInto(Temporal temporal) {
340            if (ordinal >= 0) {
341                Temporal temp = temporal.with(DAY_OF_MONTH, 1);
342                int curDow = temp.get(DAY_OF_WEEK);
343                int dowDiff = (dowValue - curDow + 7) % 7;
344                dowDiff += (ordinal - 1L) * 7L;  // safe from overflow
345                return temp.plus(dowDiff, DAYS);
346            } else {
347                Temporal temp = temporal.with(DAY_OF_MONTH, temporal.range(DAY_OF_MONTH).getMaximum());
348                int curDow = temp.get(DAY_OF_WEEK);
349                int daysDiff = dowValue - curDow;
350                daysDiff = (daysDiff == 0 ? 0 : (daysDiff > 0 ? daysDiff - 7 : daysDiff));
351                daysDiff -= (-ordinal - 1L) * 7L;  // safe from overflow
352                return temp.plus(daysDiff, DAYS);
353            }
354        }
355    }
356
357    //-----------------------------------------------------------------------
358    /**
359     * Returns the next day-of-week adjuster, which adjusts the date to the
360     * first occurrence of the specified day-of-week after the date being adjusted.
361     * <p>
362     * The ISO calendar system behaves as follows:<br>
363     * The input 2011-01-15 (a Saturday) for parameter (MONDAY) will return 2011-01-17 (two days later).<br>
364     * The input 2011-01-15 (a Saturday) for parameter (WEDNESDAY) will return 2011-01-19 (four days later).<br>
365     * The input 2011-01-15 (a Saturday) for parameter (SATURDAY) will return 2011-01-22 (seven days later).
366     * <p>
367     * The behavior is suitable for use with most calendar systems.
368     * It uses the {@code DAY_OF_WEEK} field and the {@code DAYS} unit,
369     * and assumes a seven day week.
370     *
371     * @param dayOfWeek  the day-of-week to move the date to, not null
372     * @return the next day-of-week adjuster, not null
373     */
374    public static TemporalAdjuster next(DayOfWeek dayOfWeek) {
375        return new RelativeDayOfWeek(2, dayOfWeek);
376    }
377
378    /**
379     * Returns the next-or-same day-of-week adjuster, which adjusts the date to the
380     * first occurrence of the specified day-of-week after the date being adjusted
381     * unless it is already on that day in which case the same object is returned.
382     * <p>
383     * The ISO calendar system behaves as follows:<br>
384     * The input 2011-01-15 (a Saturday) for parameter (MONDAY) will return 2011-01-17 (two days later).<br>
385     * The input 2011-01-15 (a Saturday) for parameter (WEDNESDAY) will return 2011-01-19 (four days later).<br>
386     * The input 2011-01-15 (a Saturday) for parameter (SATURDAY) will return 2011-01-15 (same as input).
387     * <p>
388     * The behavior is suitable for use with most calendar systems.
389     * It uses the {@code DAY_OF_WEEK} field and the {@code DAYS} unit,
390     * and assumes a seven day week.
391     *
392     * @param dayOfWeek  the day-of-week to check for or move the date to, not null
393     * @return the next-or-same day-of-week adjuster, not null
394     */
395    public static TemporalAdjuster nextOrSame(DayOfWeek dayOfWeek) {
396        return new RelativeDayOfWeek(0, dayOfWeek);
397    }
398
399    /**
400     * Returns the previous day-of-week adjuster, which adjusts the date to the
401     * first occurrence of the specified day-of-week before the date being adjusted.
402     * <p>
403     * The ISO calendar system behaves as follows:<br>
404     * The input 2011-01-15 (a Saturday) for parameter (MONDAY) will return 2011-01-10 (five days earlier).<br>
405     * The input 2011-01-15 (a Saturday) for parameter (WEDNESDAY) will return 2011-01-12 (three days earlier).<br>
406     * The input 2011-01-15 (a Saturday) for parameter (SATURDAY) will return 2011-01-08 (seven days earlier).
407     * <p>
408     * The behavior is suitable for use with most calendar systems.
409     * It uses the {@code DAY_OF_WEEK} field and the {@code DAYS} unit,
410     * and assumes a seven day week.
411     *
412     * @param dayOfWeek  the day-of-week to move the date to, not null
413     * @return the previous day-of-week adjuster, not null
414     */
415    public static TemporalAdjuster previous(DayOfWeek dayOfWeek) {
416        return new RelativeDayOfWeek(3, dayOfWeek);
417    }
418
419    /**
420     * Returns the previous-or-same day-of-week adjuster, which adjusts the date to the
421     * first occurrence of the specified day-of-week before the date being adjusted
422     * unless it is already on that day in which case the same object is returned.
423     * <p>
424     * The ISO calendar system behaves as follows:<br>
425     * The input 2011-01-15 (a Saturday) for parameter (MONDAY) will return 2011-01-10 (five days earlier).<br>
426     * The input 2011-01-15 (a Saturday) for parameter (WEDNESDAY) will return 2011-01-12 (three days earlier).<br>
427     * The input 2011-01-15 (a Saturday) for parameter (SATURDAY) will return 2011-01-15 (same as input).
428     * <p>
429     * The behavior is suitable for use with most calendar systems.
430     * It uses the {@code DAY_OF_WEEK} field and the {@code DAYS} unit,
431     * and assumes a seven day week.
432     *
433     * @param dayOfWeek  the day-of-week to check for or move the date to, not null
434     * @return the previous-or-same day-of-week adjuster, not null
435     */
436    public static TemporalAdjuster previousOrSame(DayOfWeek dayOfWeek) {
437        return new RelativeDayOfWeek(1, dayOfWeek);
438    }
439
440    /**
441     * Implementation of next, previous or current day-of-week.
442     */
443    private static final class RelativeDayOfWeek implements TemporalAdjuster {
444        /** Whether the current date is a valid answer. */
445        private final int relative;
446        /** The day-of-week value, from 1 to 7. */
447        private final int dowValue;
448
449        private RelativeDayOfWeek(int relative, DayOfWeek dayOfWeek) {
450            Objects.requireNonNull(dayOfWeek, "dayOfWeek");
451            this.relative = relative;
452            this.dowValue = dayOfWeek.getValue();
453        }
454
455        @Override
456        public Temporal adjustInto(Temporal temporal) {
457            int calDow = temporal.get(DAY_OF_WEEK);
458            if (relative < 2 && calDow == dowValue) {
459                return temporal;
460            }
461            if ((relative & 1) == 0) {
462                int daysDiff = calDow - dowValue;
463                return temporal.plus(daysDiff >= 0 ? 7 - daysDiff : -daysDiff, DAYS);
464            } else {
465                int daysDiff = dowValue - calDow;
466                return temporal.minus(daysDiff >= 0 ? 7 - daysDiff : -daysDiff, DAYS);
467            }
468        }
469    }
470
471}