• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 /*
27  * This file is available under and governed by the GNU General Public
28  * License version 2 only, as published by the Free Software Foundation.
29  * However, the following notice accompanied the original version of this
30  * file:
31  *
32  * Copyright (c) 2012-2013, Stephen Colebourne & Michael Nascimento Santos
33  *
34  * All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions are met:
38  *
39  *  * Redistributions of source code must retain the above copyright notice,
40  *    this list of conditions and the following disclaimer.
41  *
42  *  * Redistributions in binary form must reproduce the above copyright notice,
43  *    this list of conditions and the following disclaimer in the documentation
44  *    and/or other materials provided with the distribution.
45  *
46  *  * Neither the name of JSR-310 nor the names of its contributors
47  *    may be used to endorse or promote products derived from this software
48  *    without specific prior written permission.
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
51  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
52  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
53  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
54  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
55  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
56  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
57  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
58  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
59  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
60  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
61  */
62 package java.time.temporal;
63 
64 import static java.time.temporal.ChronoField.DAY_OF_MONTH;
65 import static java.time.temporal.ChronoField.DAY_OF_WEEK;
66 import static java.time.temporal.ChronoField.DAY_OF_YEAR;
67 import static java.time.temporal.ChronoUnit.DAYS;
68 import static java.time.temporal.ChronoUnit.MONTHS;
69 import static java.time.temporal.ChronoUnit.YEARS;
70 
71 import java.time.DayOfWeek;
72 import java.time.LocalDate;
73 import java.util.Objects;
74 import java.util.function.UnaryOperator;
75 
76 /**
77  * Common and useful TemporalAdjusters.
78  * <p>
79  * Adjusters are a key tool for modifying temporal objects.
80  * They exist to externalize the process of adjustment, permitting different
81  * approaches, as per the strategy design pattern.
82  * Examples might be an adjuster that sets the date avoiding weekends, or one that
83  * sets the date to the last day of the month.
84  * <p>
85  * There are two equivalent ways of using a {@code TemporalAdjuster}.
86  * The first is to invoke the method on the interface directly.
87  * The second is to use {@link Temporal#with(TemporalAdjuster)}:
88  * <pre>
89  *   // these two lines are equivalent, but the second approach is recommended
90  *   temporal = thisAdjuster.adjustInto(temporal);
91  *   temporal = temporal.with(thisAdjuster);
92  * </pre>
93  * It is recommended to use the second approach, {@code with(TemporalAdjuster)},
94  * as it is a lot clearer to read in code.
95  * <p>
96  * This class contains a standard set of adjusters, available as static methods.
97  * These include:
98  * <ul>
99  * <li>finding the first or last day of the month
100  * <li>finding the first day of next month
101  * <li>finding the first or last day of the year
102  * <li>finding the first day of next year
103  * <li>finding the first or last day-of-week within a month, such as "first Wednesday in June"
104  * <li>finding the next or previous day-of-week, such as "next Thursday"
105  * </ul>
106  *
107  * @implSpec
108  * All the implementations supplied by the static methods are immutable.
109  *
110  * @see TemporalAdjuster
111  * @since 1.8
112  */
113 public final class TemporalAdjusters {
114 
115     /**
116      * Private constructor since this is a utility class.
117      */
TemporalAdjusters()118     private TemporalAdjusters() {
119     }
120 
121     //-----------------------------------------------------------------------
122     /**
123      * Obtains a {@code TemporalAdjuster} that wraps a date adjuster.
124      * <p>
125      * The {@code TemporalAdjuster} is based on the low level {@code Temporal} interface.
126      * This method allows an adjustment from {@code LocalDate} to {@code LocalDate}
127      * to be wrapped to match the temporal-based interface.
128      * This is provided for convenience to make user-written adjusters simpler.
129      * <p>
130      * In general, user-written adjusters should be static constants:
131      * <pre>{@code
132      *  static TemporalAdjuster TWO_DAYS_LATER =
133      *       TemporalAdjusters.ofDateAdjuster(date -> date.plusDays(2));
134      * }</pre>
135      *
136      * @param dateBasedAdjuster  the date-based adjuster, not null
137      * @return the temporal adjuster wrapping on the date adjuster, not null
138      */
ofDateAdjuster(UnaryOperator<LocalDate> dateBasedAdjuster)139     public static TemporalAdjuster ofDateAdjuster(UnaryOperator<LocalDate> dateBasedAdjuster) {
140         Objects.requireNonNull(dateBasedAdjuster, "dateBasedAdjuster");
141         return (temporal) -> {
142             LocalDate input = LocalDate.from(temporal);
143             LocalDate output = dateBasedAdjuster.apply(input);
144             return temporal.with(output);
145         };
146     }
147 
148     //-----------------------------------------------------------------------
149     /**
150      * Returns the "first day of month" adjuster, which returns a new date set to
151      * the first day of the current month.
152      * <p>
153      * The ISO calendar system behaves as follows:<br>
154      * The input 2011-01-15 will return 2011-01-01.<br>
155      * The input 2011-02-15 will return 2011-02-01.
156      * <p>
157      * The behavior is suitable for use with most calendar systems.
158      * It is equivalent to:
159      * <pre>
160      *  temporal.with(DAY_OF_MONTH, 1);
161      * </pre>
162      *
163      * @return the first day-of-month adjuster, not null
164      */
firstDayOfMonth()165     public static TemporalAdjuster firstDayOfMonth() {
166         return (temporal) -> temporal.with(DAY_OF_MONTH, 1);
167     }
168 
169     /**
170      * Returns the "last day of month" adjuster, which returns a new date set to
171      * the last day of the current month.
172      * <p>
173      * The ISO calendar system behaves as follows:<br>
174      * The input 2011-01-15 will return 2011-01-31.<br>
175      * The input 2011-02-15 will return 2011-02-28.<br>
176      * The input 2012-02-15 will return 2012-02-29 (leap year).<br>
177      * The input 2011-04-15 will return 2011-04-30.
178      * <p>
179      * The behavior is suitable for use with most calendar systems.
180      * It is equivalent to:
181      * <pre>
182      *  long lastDay = temporal.range(DAY_OF_MONTH).getMaximum();
183      *  temporal.with(DAY_OF_MONTH, lastDay);
184      * </pre>
185      *
186      * @return the last day-of-month adjuster, not null
187      */
lastDayOfMonth()188     public static TemporalAdjuster lastDayOfMonth() {
189         return (temporal) -> temporal.with(DAY_OF_MONTH, temporal.range(DAY_OF_MONTH).getMaximum());
190     }
191 
192     /**
193      * Returns the "first day of next month" adjuster, which returns a new date set to
194      * the first day of the next month.
195      * <p>
196      * The ISO calendar system behaves as follows:<br>
197      * The input 2011-01-15 will return 2011-02-01.<br>
198      * The input 2011-02-15 will return 2011-03-01.
199      * <p>
200      * The behavior is suitable for use with most calendar systems.
201      * It is equivalent to:
202      * <pre>
203      *  temporal.with(DAY_OF_MONTH, 1).plus(1, MONTHS);
204      * </pre>
205      *
206      * @return the first day of next month adjuster, not null
207      */
firstDayOfNextMonth()208     public static TemporalAdjuster firstDayOfNextMonth() {
209         return (temporal) -> temporal.with(DAY_OF_MONTH, 1).plus(1, MONTHS);
210     }
211 
212     //-----------------------------------------------------------------------
213     /**
214      * Returns the "first day of year" adjuster, which returns a new date set to
215      * the first day of the current year.
216      * <p>
217      * The ISO calendar system behaves as follows:<br>
218      * The input 2011-01-15 will return 2011-01-01.<br>
219      * The input 2011-02-15 will return 2011-01-01.<br>
220      * <p>
221      * The behavior is suitable for use with most calendar systems.
222      * It is equivalent to:
223      * <pre>
224      *  temporal.with(DAY_OF_YEAR, 1);
225      * </pre>
226      *
227      * @return the first day-of-year adjuster, not null
228      */
firstDayOfYear()229     public static TemporalAdjuster firstDayOfYear() {
230         return (temporal) -> temporal.with(DAY_OF_YEAR, 1);
231     }
232 
233     /**
234      * Returns the "last day of year" adjuster, which returns a new date set to
235      * the last day of the current year.
236      * <p>
237      * The ISO calendar system behaves as follows:<br>
238      * The input 2011-01-15 will return 2011-12-31.<br>
239      * The input 2011-02-15 will return 2011-12-31.<br>
240      * <p>
241      * The behavior is suitable for use with most calendar systems.
242      * It is equivalent to:
243      * <pre>
244      *  long lastDay = temporal.range(DAY_OF_YEAR).getMaximum();
245      *  temporal.with(DAY_OF_YEAR, lastDay);
246      * </pre>
247      *
248      * @return the last day-of-year adjuster, not null
249      */
lastDayOfYear()250     public static TemporalAdjuster lastDayOfYear() {
251         return (temporal) -> temporal.with(DAY_OF_YEAR, temporal.range(DAY_OF_YEAR).getMaximum());
252     }
253 
254     /**
255      * Returns the "first day of next year" adjuster, which returns a new date set to
256      * the first day of the next year.
257      * <p>
258      * The ISO calendar system behaves as follows:<br>
259      * The input 2011-01-15 will return 2012-01-01.
260      * <p>
261      * The behavior is suitable for use with most calendar systems.
262      * It is equivalent to:
263      * <pre>
264      *  temporal.with(DAY_OF_YEAR, 1).plus(1, YEARS);
265      * </pre>
266      *
267      * @return the first day of next month adjuster, not null
268      */
firstDayOfNextYear()269     public static TemporalAdjuster firstDayOfNextYear() {
270         return (temporal) -> temporal.with(DAY_OF_YEAR, 1).plus(1, YEARS);
271     }
272 
273     //-----------------------------------------------------------------------
274     /**
275      * Returns the first in month adjuster, which returns a new date
276      * in the same month with the first matching day-of-week.
277      * This is used for expressions like 'first Tuesday in March'.
278      * <p>
279      * The ISO calendar system behaves as follows:<br>
280      * The input 2011-12-15 for (MONDAY) will return 2011-12-05.<br>
281      * The input 2011-12-15 for (FRIDAY) will return 2011-12-02.<br>
282      * <p>
283      * The behavior is suitable for use with most calendar systems.
284      * It uses the {@code DAY_OF_WEEK} and {@code DAY_OF_MONTH} fields
285      * and the {@code DAYS} unit, and assumes a seven day week.
286      *
287      * @param dayOfWeek  the day-of-week, not null
288      * @return the first in month adjuster, not null
289      */
firstInMonth(DayOfWeek dayOfWeek)290     public static TemporalAdjuster firstInMonth(DayOfWeek dayOfWeek) {
291         return TemporalAdjusters.dayOfWeekInMonth(1, dayOfWeek);
292     }
293 
294     /**
295      * Returns the last in month adjuster, which returns a new date
296      * in the same month with the last matching day-of-week.
297      * This is used for expressions like 'last Tuesday in March'.
298      * <p>
299      * The ISO calendar system behaves as follows:<br>
300      * The input 2011-12-15 for (MONDAY) will return 2011-12-26.<br>
301      * The input 2011-12-15 for (FRIDAY) will return 2011-12-30.<br>
302      * <p>
303      * The behavior is suitable for use with most calendar systems.
304      * It uses the {@code DAY_OF_WEEK} and {@code DAY_OF_MONTH} fields
305      * and the {@code DAYS} unit, and assumes a seven day week.
306      *
307      * @param dayOfWeek  the day-of-week, not null
308      * @return the first in month adjuster, not null
309      */
lastInMonth(DayOfWeek dayOfWeek)310     public static TemporalAdjuster lastInMonth(DayOfWeek dayOfWeek) {
311         return TemporalAdjusters.dayOfWeekInMonth(-1, dayOfWeek);
312     }
313 
314     /**
315      * Returns the day-of-week in month adjuster, which returns a new date
316      * in the same month with the ordinal day-of-week.
317      * This is used for expressions like the 'second Tuesday in March'.
318      * <p>
319      * The ISO calendar system behaves as follows:<br>
320      * The input 2011-12-15 for (1,TUESDAY) will return 2011-12-06.<br>
321      * The input 2011-12-15 for (2,TUESDAY) will return 2011-12-13.<br>
322      * The input 2011-12-15 for (3,TUESDAY) will return 2011-12-20.<br>
323      * The input 2011-12-15 for (4,TUESDAY) will return 2011-12-27.<br>
324      * The input 2011-12-15 for (5,TUESDAY) will return 2012-01-03.<br>
325      * The input 2011-12-15 for (-1,TUESDAY) will return 2011-12-27 (last in month).<br>
326      * The input 2011-12-15 for (-4,TUESDAY) will return 2011-12-06 (3 weeks before last in month).<br>
327      * The input 2011-12-15 for (-5,TUESDAY) will return 2011-11-29 (4 weeks before last in month).<br>
328      * The input 2011-12-15 for (0,TUESDAY) will return 2011-11-29 (last in previous month).<br>
329      * <p>
330      * For a positive or zero ordinal, the algorithm is equivalent to finding the first
331      * day-of-week that matches within the month and then adding a number of weeks to it.
332      * For a negative ordinal, the algorithm is equivalent to finding the last
333      * day-of-week that matches within the month and then subtracting a number of weeks to it.
334      * The ordinal number of weeks is not validated and is interpreted leniently
335      * according to this algorithm. This definition means that an ordinal of zero finds
336      * the last matching day-of-week in the previous month.
337      * <p>
338      * The behavior is suitable for use with most calendar systems.
339      * It uses the {@code DAY_OF_WEEK} and {@code DAY_OF_MONTH} fields
340      * and the {@code DAYS} unit, and assumes a seven day week.
341      *
342      * @param ordinal  the week within the month, unbounded but typically from -5 to 5
343      * @param dayOfWeek  the day-of-week, not null
344      * @return the day-of-week in month adjuster, not null
345      */
dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek)346     public static TemporalAdjuster dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek) {
347         Objects.requireNonNull(dayOfWeek, "dayOfWeek");
348         int dowValue = dayOfWeek.getValue();
349         if (ordinal >= 0) {
350             return (temporal) -> {
351                 Temporal temp = temporal.with(DAY_OF_MONTH, 1);
352                 int curDow = temp.get(DAY_OF_WEEK);
353                 int dowDiff = (dowValue - curDow + 7) % 7;
354                 dowDiff += (ordinal - 1L) * 7L;  // safe from overflow
355                 return temp.plus(dowDiff, DAYS);
356             };
357         } else {
358             return (temporal) -> {
359                 Temporal temp = temporal.with(DAY_OF_MONTH, temporal.range(DAY_OF_MONTH).getMaximum());
360                 int curDow = temp.get(DAY_OF_WEEK);
361                 int daysDiff = dowValue - curDow;
362                 daysDiff = (daysDiff == 0 ? 0 : (daysDiff > 0 ? daysDiff - 7 : daysDiff));
363                 daysDiff -= (-ordinal - 1L) * 7L;  // safe from overflow
364                 return temp.plus(daysDiff, DAYS);
365             };
366         }
367     }
368 
369     //-----------------------------------------------------------------------
370     /**
371      * Returns the next day-of-week adjuster, which adjusts the date to the
372      * first occurrence of the specified day-of-week after the date being adjusted.
373      * <p>
374      * The ISO calendar system behaves as follows:<br>
375      * The input 2011-01-15 (a Saturday) for parameter (MONDAY) will return 2011-01-17 (two days later).<br>
376      * The input 2011-01-15 (a Saturday) for parameter (WEDNESDAY) will return 2011-01-19 (four days later).<br>
377      * The input 2011-01-15 (a Saturday) for parameter (SATURDAY) will return 2011-01-22 (seven days later).
378      * <p>
379      * The behavior is suitable for use with most calendar systems.
380      * It uses the {@code DAY_OF_WEEK} field and the {@code DAYS} unit,
381      * and assumes a seven day week.
382      *
383      * @param dayOfWeek  the day-of-week to move the date to, not null
384      * @return the next day-of-week adjuster, not null
385      */
386     public static TemporalAdjuster next(DayOfWeek dayOfWeek) {
387         int dowValue = dayOfWeek.getValue();
388         return (temporal) -> {
389             int calDow = temporal.get(DAY_OF_WEEK);
390             int daysDiff = calDow - dowValue;
391             return temporal.plus(daysDiff >= 0 ? 7 - daysDiff : -daysDiff, DAYS);
392         };
393     }
394 
395     /**
396      * Returns the next-or-same day-of-week adjuster, which adjusts the date to the
397      * first occurrence of the specified day-of-week after the date being adjusted
398      * unless it is already on that day in which case the same object is returned.
399      * <p>
400      * The ISO calendar system behaves as follows:<br>
401      * The input 2011-01-15 (a Saturday) for parameter (MONDAY) will return 2011-01-17 (two days later).<br>
402      * The input 2011-01-15 (a Saturday) for parameter (WEDNESDAY) will return 2011-01-19 (four days later).<br>
403      * The input 2011-01-15 (a Saturday) for parameter (SATURDAY) will return 2011-01-15 (same as input).
404      * <p>
405      * The behavior is suitable for use with most calendar systems.
406      * It uses the {@code DAY_OF_WEEK} field and the {@code DAYS} unit,
407      * and assumes a seven day week.
408      *
409      * @param dayOfWeek  the day-of-week to check for or move the date to, not null
410      * @return the next-or-same day-of-week adjuster, not null
411      */
412     public static TemporalAdjuster nextOrSame(DayOfWeek dayOfWeek) {
413         int dowValue = dayOfWeek.getValue();
414         return (temporal) -> {
415             int calDow = temporal.get(DAY_OF_WEEK);
416             if (calDow == dowValue) {
417                 return temporal;
418             }
419             int daysDiff = calDow - dowValue;
420             return temporal.plus(daysDiff >= 0 ? 7 - daysDiff : -daysDiff, DAYS);
421         };
422     }
423 
424     /**
425      * Returns the previous day-of-week adjuster, which adjusts the date to the
426      * first occurrence of the specified day-of-week before the date being adjusted.
427      * <p>
428      * The ISO calendar system behaves as follows:<br>
429      * The input 2011-01-15 (a Saturday) for parameter (MONDAY) will return 2011-01-10 (five days earlier).<br>
430      * The input 2011-01-15 (a Saturday) for parameter (WEDNESDAY) will return 2011-01-12 (three days earlier).<br>
431      * The input 2011-01-15 (a Saturday) for parameter (SATURDAY) will return 2011-01-08 (seven days earlier).
432      * <p>
433      * The behavior is suitable for use with most calendar systems.
434      * It uses the {@code DAY_OF_WEEK} field and the {@code DAYS} unit,
435      * and assumes a seven day week.
436      *
437      * @param dayOfWeek  the day-of-week to move the date to, not null
438      * @return the previous day-of-week adjuster, not null
439      */
440     public static TemporalAdjuster previous(DayOfWeek dayOfWeek) {
441         int dowValue = dayOfWeek.getValue();
442         return (temporal) -> {
443             int calDow = temporal.get(DAY_OF_WEEK);
444             int daysDiff = dowValue - calDow;
445             return temporal.minus(daysDiff >= 0 ? 7 - daysDiff : -daysDiff, DAYS);
446         };
447     }
448 
449     /**
450      * Returns the previous-or-same day-of-week adjuster, which adjusts the date to the
451      * first occurrence of the specified day-of-week before the date being adjusted
452      * unless it is already on that day in which case the same object is returned.
453      * <p>
454      * The ISO calendar system behaves as follows:<br>
455      * The input 2011-01-15 (a Saturday) for parameter (MONDAY) will return 2011-01-10 (five days earlier).<br>
456      * The input 2011-01-15 (a Saturday) for parameter (WEDNESDAY) will return 2011-01-12 (three days earlier).<br>
457      * The input 2011-01-15 (a Saturday) for parameter (SATURDAY) will return 2011-01-15 (same as input).
458      * <p>
459      * The behavior is suitable for use with most calendar systems.
460      * It uses the {@code DAY_OF_WEEK} field and the {@code DAYS} unit,
461      * and assumes a seven day week.
462      *
463      * @param dayOfWeek  the day-of-week to check for or move the date to, not null
464      * @return the previous-or-same day-of-week adjuster, not null
465      */
466     public static TemporalAdjuster previousOrSame(DayOfWeek dayOfWeek) {
467         int dowValue = dayOfWeek.getValue();
468         return (temporal) -> {
469             int calDow = temporal.get(DAY_OF_WEEK);
470             if (calDow == dowValue) {
471                 return temporal;
472             }
473             int daysDiff = dowValue - calDow;
474             return temporal.minus(daysDiff >= 0 ? 7 - daysDiff : -daysDiff, DAYS);
475         };
476     }
477 
478 }
479