Home | History | Annotate | Download | only in temporal
      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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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