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) 2007-2012, 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.util.Objects; 73 74 /** 75 * Common implementations of {@code TemporalAdjuster}. 76 * <p> 77 * This class provides common implementations of {@link TemporalAdjuster}. 78 * They are especially useful to document the intent of business logic and 79 * often link well to requirements. 80 * For example, these two pieces of code do the same thing, but the second 81 * one is clearer (assuming that there is a static import of this class): 82 * <pre> 83 * // direct manipulation 84 * date.withDayOfMonth(1).plusMonths(1).minusDays(1); 85 * // use of an adjuster from this class 86 * date.with(lastDayOfMonth()); 87 * </pre> 88 * There are two equivalent ways of using a {@code TemporalAdjuster}. 89 * The first is to invoke the method on the interface directly. 90 * The second is to use {@link Temporal#with(TemporalAdjuster)}: 91 * <pre> 92 * // these two lines are equivalent, but the second approach is recommended 93 * dateTime = adjuster.adjustInto(dateTime); 94 * dateTime = dateTime.with(adjuster); 95 * </pre> 96 * It is recommended to use the second approach, {@code with(TemporalAdjuster)}, 97 * as it is a lot clearer to read in code. 98 * 99 * <h3>Specification for implementors</h3> 100 * This is a thread-safe utility class. 101 * All returned adjusters are immutable and thread-safe. 102 * 103 * @since 1.8 104 */ 105 public final class Adjusters { 106 107 /** 108 * Private constructor since this is a utility class. 109 */ 110 private Adjusters() { 111 } 112 113 //----------------------------------------------------------------------- 114 /** 115 * Returns the "first day of month" adjuster, which returns a new date set to 116 * the first day of the current month. 117 * <p> 118 * The ISO calendar system behaves as follows:<br> 119 * The input 2011-01-15 will return 2011-01-01.<br> 120 * The input 2011-02-15 will return 2011-02-01. 121 * <p> 122 * The behavior is suitable for use with most calendar systems. 123 * It is equivalent to: 124 * <pre> 125 * temporal.with(DAY_OF_MONTH, 1); 126 * </pre> 127 * 128 * @return the first day-of-month adjuster, not null 129 */ 130 public static TemporalAdjuster firstDayOfMonth() { 131 return Impl.FIRST_DAY_OF_MONTH; 132 } 133 134 /** 135 * Returns the "last day of month" adjuster, which returns a new date set to 136 * the last day of the current month. 137 * <p> 138 * The ISO calendar system behaves as follows:<br> 139 * The input 2011-01-15 will return 2011-01-31.<br> 140 * The input 2011-02-15 will return 2011-02-28.<br> 141 * The input 2012-02-15 will return 2012-02-29 (leap year).<br> 142 * The input 2011-04-15 will return 2011-04-30. 143 * <p> 144 * The behavior is suitable for use with most calendar systems. 145 * It is equivalent to: 146 * <pre> 147 * long lastDay = temporal.range(DAY_OF_MONTH).getMaximum(); 148 * temporal.with(DAY_OF_MONTH, lastDay); 149 * </pre> 150 * 151 * @return the last day-of-month adjuster, not null 152 */ 153 public static TemporalAdjuster lastDayOfMonth() { 154 return Impl.LAST_DAY_OF_MONTH; 155 } 156 157 /** 158 * Returns the "first day of next month" adjuster, which returns a new date set to 159 * the first day of the next month. 160 * <p> 161 * The ISO calendar system behaves as follows:<br> 162 * The input 2011-01-15 will return 2011-02-01.<br> 163 * The input 2011-02-15 will return 2011-03-01. 164 * <p> 165 * The behavior is suitable for use with most calendar systems. 166 * It is equivalent to: 167 * <pre> 168 * temporal.with(DAY_OF_MONTH, 1).plus(1, MONTHS); 169 * </pre> 170 * 171 * @return the first day of next month adjuster, not null 172 */ 173 public static TemporalAdjuster firstDayOfNextMonth() { 174 return Impl.FIRST_DAY_OF_NEXT_MONTH; 175 } 176 177 //----------------------------------------------------------------------- 178 /** 179 * Returns the "first day of year" adjuster, which returns a new date set to 180 * the first day of the current year. 181 * <p> 182 * The ISO calendar system behaves as follows:<br> 183 * The input 2011-01-15 will return 2011-01-01.<br> 184 * The input 2011-02-15 will return 2011-01-01.<br> 185 * <p> 186 * The behavior is suitable for use with most calendar systems. 187 * It is equivalent to: 188 * <pre> 189 * temporal.with(DAY_OF_YEAR, 1); 190 * </pre> 191 * 192 * @return the first day-of-year adjuster, not null 193 */ 194 public static TemporalAdjuster firstDayOfYear() { 195 return Impl.FIRST_DAY_OF_YEAR; 196 } 197 198 /** 199 * Returns the "last day of year" adjuster, which returns a new date set to 200 * the last day of the current year. 201 * <p> 202 * The ISO calendar system behaves as follows:<br> 203 * The input 2011-01-15 will return 2011-12-31.<br> 204 * The input 2011-02-15 will return 2011-12-31.<br> 205 * <p> 206 * The behavior is suitable for use with most calendar systems. 207 * It is equivalent to: 208 * <pre> 209 * long lastDay = temporal.range(DAY_OF_YEAR).getMaximum(); 210 * temporal.with(DAY_OF_YEAR, lastDay); 211 * </pre> 212 * 213 * @return the last day-of-year adjuster, not null 214 */ 215 public static TemporalAdjuster lastDayOfYear() { 216 return Impl.LAST_DAY_OF_YEAR; 217 } 218 219 /** 220 * Returns the "first day of next year" adjuster, which returns a new date set to 221 * the first day of the next year. 222 * <p> 223 * The ISO calendar system behaves as follows:<br> 224 * The input 2011-01-15 will return 2012-01-01. 225 * <p> 226 * The behavior is suitable for use with most calendar systems. 227 * It is equivalent to: 228 * <pre> 229 * temporal.with(DAY_OF_YEAR, 1).plus(1, YEARS); 230 * </pre> 231 * 232 * @return the first day of next month adjuster, not null 233 */ 234 public static TemporalAdjuster firstDayOfNextYear() { 235 return Impl.FIRST_DAY_OF_NEXT_YEAR; 236 } 237 238 //----------------------------------------------------------------------- 239 /** 240 * Enum implementing the adjusters. 241 */ 242 private static class Impl implements TemporalAdjuster { 243 /** First day of month adjuster. */ 244 private static final Impl FIRST_DAY_OF_MONTH = new Impl(0); 245 /** Last day of month adjuster. */ 246 private static final Impl LAST_DAY_OF_MONTH = new Impl(1); 247 /** First day of next month adjuster. */ 248 private static final Impl FIRST_DAY_OF_NEXT_MONTH = new Impl(2); 249 /** First day of year adjuster. */ 250 private static final Impl FIRST_DAY_OF_YEAR = new Impl(3); 251 /** Last day of year adjuster. */ 252 private static final Impl LAST_DAY_OF_YEAR = new Impl(4); 253 /** First day of next month adjuster. */ 254 private static final Impl FIRST_DAY_OF_NEXT_YEAR = new Impl(5); 255 /** The ordinal. */ 256 private final int ordinal; 257 private Impl(int ordinal) { 258 this.ordinal = ordinal; 259 } 260 @Override 261 public Temporal adjustInto(Temporal temporal) { 262 switch (ordinal) { 263 case 0: return temporal.with(DAY_OF_MONTH, 1); 264 case 1: return temporal.with(DAY_OF_MONTH, temporal.range(DAY_OF_MONTH).getMaximum()); 265 case 2: return temporal.with(DAY_OF_MONTH, 1).plus(1, MONTHS); 266 case 3: return temporal.with(DAY_OF_YEAR, 1); 267 case 4: return temporal.with(DAY_OF_YEAR, temporal.range(DAY_OF_YEAR).getMaximum()); 268 case 5: return temporal.with(DAY_OF_YEAR, 1).plus(1, YEARS); 269 } 270 throw new IllegalStateException("Unreachable"); 271 } 272 } 273 274 //----------------------------------------------------------------------- 275 /** 276 * Returns the first in month adjuster, which returns a new date 277 * in the same month with the first matching day-of-week. 278 * This is used for expressions like 'first Tuesday in March'. 279 * <p> 280 * The ISO calendar system behaves as follows:<br> 281 * The input 2011-12-15 for (MONDAY) will return 2011-12-05.<br> 282 * The input 2011-12-15 for (FRIDAY) will return 2011-12-02.<br> 283 * <p> 284 * The behavior is suitable for use with most calendar systems. 285 * It uses the {@code DAY_OF_WEEK} and {@code DAY_OF_MONTH} fields 286 * and the {@code DAYS} unit, and assumes a seven day week. 287 * 288 * @param dayOfWeek the day-of-week, not null 289 * @return the first in month adjuster, not null 290 */ 291 public static TemporalAdjuster firstInMonth(DayOfWeek dayOfWeek) { 292 Objects.requireNonNull(dayOfWeek, "dayOfWeek"); 293 return new DayOfWeekInMonth(1, dayOfWeek); 294 } 295 296 /** 297 * Returns the last in month adjuster, which returns a new date 298 * in the same month with the last matching day-of-week. 299 * This is used for expressions like 'last Tuesday in March'. 300 * <p> 301 * The ISO calendar system behaves as follows:<br> 302 * The input 2011-12-15 for (MONDAY) will return 2011-12-26.<br> 303 * The input 2011-12-15 for (FRIDAY) will return 2011-12-30.<br> 304 * <p> 305 * The behavior is suitable for use with most calendar systems. 306 * It uses the {@code DAY_OF_WEEK} and {@code DAY_OF_MONTH} fields 307 * and the {@code DAYS} unit, and assumes a seven day week. 308 * 309 * @param dayOfWeek the day-of-week, not null 310 * @return the first in month adjuster, not null 311 */ 312 public static TemporalAdjuster lastInMonth(DayOfWeek dayOfWeek) { 313 Objects.requireNonNull(dayOfWeek, "dayOfWeek"); 314 return new DayOfWeekInMonth(-1, dayOfWeek); 315 } 316 317 /** 318 * Returns the day-of-week in month adjuster, which returns a new date 319 * in the same month with the ordinal day-of-week. 320 * This is used for expressions like the 'second Tuesday in March'. 321 * <p> 322 * The ISO calendar system behaves as follows:<br> 323 * The input 2011-12-15 for (1,TUESDAY) will return 2011-12-06.<br> 324 * The input 2011-12-15 for (2,TUESDAY) will return 2011-12-13.<br> 325 * The input 2011-12-15 for (3,TUESDAY) will return 2011-12-20.<br> 326 * The input 2011-12-15 for (4,TUESDAY) will return 2011-12-27.<br> 327 * The input 2011-12-15 for (5,TUESDAY) will return 2012-01-03.<br> 328 * The input 2011-12-15 for (-1,TUESDAY) will return 2011-12-27 (last in month).<br> 329 * The input 2011-12-15 for (-4,TUESDAY) will return 2011-12-06 (3 weeks before last in month).<br> 330 * The input 2011-12-15 for (-5,TUESDAY) will return 2011-11-29 (4 weeks before last in month).<br> 331 * The input 2011-12-15 for (0,TUESDAY) will return 2011-11-29 (last in previous month).<br> 332 * <p> 333 * For a positive or zero ordinal, the algorithm is equivalent to finding the first 334 * day-of-week that matches within the month and then adding a number of weeks to it. 335 * For a negative ordinal, the algorithm is equivalent to finding the last 336 * day-of-week that matches within the month and then subtracting a number of weeks to it. 337 * The ordinal number of weeks is not validated and is interpreted leniently 338 * according to this algorithm. This definition means that an ordinal of zero finds 339 * the last matching day-of-week in the previous month. 340 * <p> 341 * The behavior is suitable for use with most calendar systems. 342 * It uses the {@code DAY_OF_WEEK} and {@code DAY_OF_MONTH} fields 343 * and the {@code DAYS} unit, and assumes a seven day week. 344 * 345 * @param ordinal the week within the month, unbound but typically from -5 to 5 346 * @param dayOfWeek the day-of-week, not null 347 * @return the day-of-week in month adjuster, not null 348 * @throws IllegalArgumentException if the ordinal is invalid 349 */ 350 public static TemporalAdjuster dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek) { 351 Objects.requireNonNull(dayOfWeek, "dayOfWeek"); 352 return new DayOfWeekInMonth(ordinal, dayOfWeek); 353 } 354 355 /** 356 * Class implementing day-of-week in month adjuster. 357 */ 358 private static final class DayOfWeekInMonth implements TemporalAdjuster { 359 /** The ordinal. */ 360 private final int ordinal; 361 /** The day-of-week value, from 1 to 7. */ 362 private final int dowValue; 363 364 private DayOfWeekInMonth(int ordinal, DayOfWeek dow) { 365 super(); 366 this.ordinal = ordinal; 367 this.dowValue = dow.getValue(); 368 } 369 @Override 370 public Temporal adjustInto(Temporal temporal) { 371 if (ordinal >= 0) { 372 Temporal temp = temporal.with(DAY_OF_MONTH, 1); 373 int curDow = temp.get(DAY_OF_WEEK); 374 int dowDiff = (dowValue - curDow + 7) % 7; 375 dowDiff += (ordinal - 1L) * 7L; // safe from overflow 376 return temp.plus(dowDiff, DAYS); 377 } else { 378 Temporal temp = temporal.with(DAY_OF_MONTH, temporal.range(DAY_OF_MONTH).getMaximum()); 379 int curDow = temp.get(DAY_OF_WEEK); 380 int daysDiff = dowValue - curDow; 381 daysDiff = (daysDiff == 0 ? 0 : (daysDiff > 0 ? daysDiff - 7 : daysDiff)); 382 daysDiff -= (-ordinal - 1L) * 7L; // safe from overflow 383 return temp.plus(daysDiff, DAYS); 384 } 385 } 386 } 387 388 //----------------------------------------------------------------------- 389 /** 390 * Returns the next day-of-week adjuster, which adjusts the date to the 391 * first occurrence of the specified day-of-week after the date being adjusted. 392 * <p> 393 * The ISO calendar system behaves as follows:<br> 394 * The input 2011-01-15 (a Saturday) for parameter (MONDAY) will return 2011-01-17 (two days later).<br> 395 * The input 2011-01-15 (a Saturday) for parameter (WEDNESDAY) will return 2011-01-19 (four days later).<br> 396 * The input 2011-01-15 (a Saturday) for parameter (SATURDAY) will return 2011-01-22 (seven days later). 397 * <p> 398 * The behavior is suitable for use with most calendar systems. 399 * It uses the {@code DAY_OF_WEEK} field and the {@code DAYS} unit, 400 * and assumes a seven day week. 401 * 402 * @param dayOfWeek the day-of-week to move the date to, not null 403 * @return the next day-of-week adjuster, not null 404 */ 405 public static TemporalAdjuster next(DayOfWeek dayOfWeek) { 406 return new RelativeDayOfWeek(2, dayOfWeek); 407 } 408 409 /** 410 * Returns the next-or-same day-of-week adjuster, which adjusts the date to the 411 * first occurrence of the specified day-of-week after the date being adjusted 412 * unless it is already on that day in which case the same object is returned. 413 * <p> 414 * The ISO calendar system behaves as follows:<br> 415 * The input 2011-01-15 (a Saturday) for parameter (MONDAY) will return 2011-01-17 (two days later).<br> 416 * The input 2011-01-15 (a Saturday) for parameter (WEDNESDAY) will return 2011-01-19 (four days later).<br> 417 * The input 2011-01-15 (a Saturday) for parameter (SATURDAY) will return 2011-01-15 (same as input). 418 * <p> 419 * The behavior is suitable for use with most calendar systems. 420 * It uses the {@code DAY_OF_WEEK} field and the {@code DAYS} unit, 421 * and assumes a seven day week. 422 * 423 * @param dayOfWeek the day-of-week to check for or move the date to, not null 424 * @return the next-or-same day-of-week adjuster, not null 425 */ 426 public static TemporalAdjuster nextOrSame(DayOfWeek dayOfWeek) { 427 return new RelativeDayOfWeek(0, dayOfWeek); 428 } 429 430 /** 431 * Returns the previous day-of-week adjuster, which adjusts the date to the 432 * first occurrence of the specified day-of-week before the date being adjusted. 433 * <p> 434 * The ISO calendar system behaves as follows:<br> 435 * The input 2011-01-15 (a Saturday) for parameter (MONDAY) will return 2011-01-10 (five days earlier).<br> 436 * The input 2011-01-15 (a Saturday) for parameter (WEDNESDAY) will return 2011-01-12 (three days earlier).<br> 437 * The input 2011-01-15 (a Saturday) for parameter (SATURDAY) will return 2011-01-08 (seven days earlier). 438 * <p> 439 * The behavior is suitable for use with most calendar systems. 440 * It uses the {@code DAY_OF_WEEK} field and the {@code DAYS} unit, 441 * and assumes a seven day week. 442 * 443 * @param dayOfWeek the day-of-week to move the date to, not null 444 * @return the previous day-of-week adjuster, not null 445 */ 446 public static TemporalAdjuster previous(DayOfWeek dayOfWeek) { 447 return new RelativeDayOfWeek(3, dayOfWeek); 448 } 449 450 /** 451 * Returns the previous-or-same day-of-week adjuster, which adjusts the date to the 452 * first occurrence of the specified day-of-week before the date being adjusted 453 * unless it is already on that day in which case the same object is returned. 454 * <p> 455 * The ISO calendar system behaves as follows:<br> 456 * The input 2011-01-15 (a Saturday) for parameter (MONDAY) will return 2011-01-10 (five days earlier).<br> 457 * The input 2011-01-15 (a Saturday) for parameter (WEDNESDAY) will return 2011-01-12 (three days earlier).<br> 458 * The input 2011-01-15 (a Saturday) for parameter (SATURDAY) will return 2011-01-15 (same as input). 459 * <p> 460 * The behavior is suitable for use with most calendar systems. 461 * It uses the {@code DAY_OF_WEEK} field and the {@code DAYS} unit, 462 * and assumes a seven day week. 463 * 464 * @param dayOfWeek the day-of-week to check for or move the date to, not null 465 * @return the previous-or-same day-of-week adjuster, not null 466 */ 467 public static TemporalAdjuster previousOrSame(DayOfWeek dayOfWeek) { 468 return new RelativeDayOfWeek(1, dayOfWeek); 469 } 470 471 /** 472 * Implementation of next, previous or current day-of-week. 473 */ 474 private static final class RelativeDayOfWeek implements TemporalAdjuster { 475 /** Whether the current date is a valid answer. */ 476 private final int relative; 477 /** The day-of-week value, from 1 to 7. */ 478 private final int dowValue; 479 480 private RelativeDayOfWeek(int relative, DayOfWeek dayOfWeek) { 481 Objects.requireNonNull(dayOfWeek, "dayOfWeek"); 482 this.relative = relative; 483 this.dowValue = dayOfWeek.getValue(); 484 } 485 486 @Override 487 public Temporal adjustInto(Temporal temporal) { 488 int calDow = temporal.get(DAY_OF_WEEK); 489 if (relative < 2 && calDow == dowValue) { 490 return temporal; 491 } 492 if ((relative & 1) == 0) { 493 int daysDiff = calDow - dowValue; 494 return temporal.plus(daysDiff >= 0 ? 7 - daysDiff : -daysDiff, DAYS); 495 } else { 496 int daysDiff = dowValue - calDow; 497 return temporal.minus(daysDiff >= 0 ? 7 - daysDiff : -daysDiff, DAYS); 498 } 499 } 500 } 501 502 }