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}