1 /* 2 * Copyright (c) 2007-present, Stephen Colebourne & Michael Nascimento Santos 3 * 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * * Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 12 * * Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * * Neither the name of JSR-310 nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package org.threeten.bp; 33 34 import static org.threeten.bp.temporal.ChronoField.DAY_OF_WEEK; 35 import static org.threeten.bp.temporal.ChronoUnit.DAYS; 36 37 import java.util.Locale; 38 39 import org.threeten.bp.format.DateTimeFormatterBuilder; 40 import org.threeten.bp.format.TextStyle; 41 import org.threeten.bp.temporal.ChronoField; 42 import org.threeten.bp.temporal.Temporal; 43 import org.threeten.bp.temporal.TemporalAccessor; 44 import org.threeten.bp.temporal.TemporalAdjuster; 45 import org.threeten.bp.temporal.TemporalAdjusters; 46 import org.threeten.bp.temporal.TemporalField; 47 import org.threeten.bp.temporal.TemporalQueries; 48 import org.threeten.bp.temporal.TemporalQuery; 49 import org.threeten.bp.temporal.UnsupportedTemporalTypeException; 50 import org.threeten.bp.temporal.ValueRange; 51 import org.threeten.bp.temporal.WeekFields; 52 53 /** 54 * A day-of-week, such as 'Tuesday'. 55 * <p> 56 * {@code DayOfWeek} is an enum representing the 7 days of the week - 57 * Monday, Tuesday, Wednesday, Thursday, Friday, Saturday and Sunday. 58 * <p> 59 * In addition to the textual enum name, each day-of-week has an {@code int} value. 60 * The {@code int} value follows the ISO-8601 standard, from 1 (Monday) to 7 (Sunday). 61 * It is recommended that applications use the enum rather than the {@code int} value 62 * to ensure code clarity. 63 * <p> 64 * This enum provides access to the localized textual form of the day-of-week. 65 * Some locales also assign different numeric values to the days, declaring 66 * Sunday to have the value 1, however this class provides no support for this. 67 * See {@link WeekFields} for localized week-numbering. 68 * <p> 69 * <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code DayOfWeek}. 70 * Use {@code getValue()} instead.</b> 71 * <p> 72 * This enum represents a common concept that is found in many calendar systems. 73 * As such, this enum may be used by any calendar system that has the day-of-week 74 * concept defined exactly equivalent to the ISO calendar system. 75 * 76 * <h3>Specification for implementors</h3> 77 * This is an immutable and thread-safe enum. 78 */ 79 public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster { 80 81 /** 82 * The singleton instance for the day-of-week of Monday. 83 * This has the numeric value of {@code 1}. 84 */ 85 MONDAY, 86 /** 87 * The singleton instance for the day-of-week of Tuesday. 88 * This has the numeric value of {@code 2}. 89 */ 90 TUESDAY, 91 /** 92 * The singleton instance for the day-of-week of Wednesday. 93 * This has the numeric value of {@code 3}. 94 */ 95 WEDNESDAY, 96 /** 97 * The singleton instance for the day-of-week of Thursday. 98 * This has the numeric value of {@code 4}. 99 */ 100 THURSDAY, 101 /** 102 * The singleton instance for the day-of-week of Friday. 103 * This has the numeric value of {@code 5}. 104 */ 105 FRIDAY, 106 /** 107 * The singleton instance for the day-of-week of Saturday. 108 * This has the numeric value of {@code 6}. 109 */ 110 SATURDAY, 111 /** 112 * The singleton instance for the day-of-week of Sunday. 113 * This has the numeric value of {@code 7}. 114 */ 115 SUNDAY; 116 /** 117 * Simulate JDK 8 method reference DayOfWeek::from. 118 */ 119 public static final TemporalQuery<DayOfWeek> FROM = new TemporalQuery<DayOfWeek>() { 120 @Override 121 public DayOfWeek queryFrom(TemporalAccessor temporal) { 122 return DayOfWeek.from(temporal); 123 } 124 }; 125 /** 126 * Private cache of all the constants. 127 */ 128 private static final DayOfWeek[] ENUMS = DayOfWeek.values(); 129 130 //----------------------------------------------------------------------- 131 /** 132 * Obtains an instance of {@code DayOfWeek} from an {@code int} value. 133 * <p> 134 * {@code DayOfWeek} is an enum representing the 7 days of the week. 135 * This factory allows the enum to be obtained from the {@code int} value. 136 * The {@code int} value follows the ISO-8601 standard, from 1 (Monday) to 7 (Sunday). 137 * 138 * @param dayOfWeek the day-of-week to represent, from 1 (Monday) to 7 (Sunday) 139 * @return the day-of-week singleton, not null 140 * @throws DateTimeException if the day-of-week is invalid 141 */ of(int dayOfWeek)142 public static DayOfWeek of(int dayOfWeek) { 143 if (dayOfWeek < 1 || dayOfWeek > 7) { 144 throw new DateTimeException("Invalid value for DayOfWeek: " + dayOfWeek); 145 } 146 return ENUMS[dayOfWeek - 1]; 147 } 148 149 //----------------------------------------------------------------------- 150 /** 151 * Obtains an instance of {@code DayOfWeek} from a temporal object. 152 * <p> 153 * A {@code TemporalAccessor} represents some form of date and time information. 154 * This factory converts the arbitrary temporal object to an instance of {@code DayOfWeek}. 155 * <p> 156 * The conversion extracts the {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} field. 157 * <p> 158 * This method matches the signature of the functional interface {@link TemporalQuery} 159 * allowing it to be used as a query via method reference, {@code DayOfWeek::from}. 160 * 161 * @param temporal the temporal object to convert, not null 162 * @return the day-of-week, not null 163 * @throws DateTimeException if unable to convert to a {@code DayOfWeek} 164 */ from(TemporalAccessor temporal)165 public static DayOfWeek from(TemporalAccessor temporal) { 166 if (temporal instanceof DayOfWeek) { 167 return (DayOfWeek) temporal; 168 } 169 try { 170 return of(temporal.get(DAY_OF_WEEK)); 171 } catch (DateTimeException ex) { 172 throw new DateTimeException("Unable to obtain DayOfWeek from TemporalAccessor: " + 173 temporal + ", type " + temporal.getClass().getName(), ex); 174 } 175 } 176 177 //----------------------------------------------------------------------- 178 /** 179 * Gets the day-of-week {@code int} value. 180 * <p> 181 * The values are numbered following the ISO-8601 standard, from 1 (Monday) to 7 (Sunday). 182 * See {@link WeekFields#dayOfWeek} for localized week-numbering. 183 * 184 * @return the day-of-week, from 1 (Monday) to 7 (Sunday) 185 */ getValue()186 public int getValue() { 187 return ordinal() + 1; 188 } 189 190 //----------------------------------------------------------------------- 191 /** 192 * Gets the textual representation, such as 'Mon' or 'Friday'. 193 * <p> 194 * This returns the textual name used to identify the day-of-week. 195 * The parameters control the length of the returned text and the locale. 196 * <p> 197 * If no textual mapping is found then the {@link #getValue() numeric value} is returned. 198 * 199 * @param style the length of the text required, not null 200 * @param locale the locale to use, not null 201 * @return the text value of the day-of-week, not null 202 */ getDisplayName(TextStyle style, Locale locale)203 public String getDisplayName(TextStyle style, Locale locale) { 204 return new DateTimeFormatterBuilder().appendText(DAY_OF_WEEK, style).toFormatter(locale).format(this); 205 } 206 207 //----------------------------------------------------------------------- 208 /** 209 * Checks if the specified field is supported. 210 * <p> 211 * This checks if this day-of-week can be queried for the specified field. 212 * If false, then calling the {@link #range(TemporalField) range} and 213 * {@link #get(TemporalField) get} methods will throw an exception. 214 * <p> 215 * If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then 216 * this method returns true. 217 * All other {@code ChronoField} instances will return false. 218 * <p> 219 * If the field is not a {@code ChronoField}, then the result of this method 220 * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)} 221 * passing {@code this} as the argument. 222 * Whether the field is supported is determined by the field. 223 * 224 * @param field the field to check, null returns false 225 * @return true if the field is supported on this day-of-week, false if not 226 */ 227 @Override isSupported(TemporalField field)228 public boolean isSupported(TemporalField field) { 229 if (field instanceof ChronoField) { 230 return field == DAY_OF_WEEK; 231 } 232 return field != null && field.isSupportedBy(this); 233 } 234 235 /** 236 * Gets the range of valid values for the specified field. 237 * <p> 238 * The range object expresses the minimum and maximum valid values for a field. 239 * This day-of-week is used to enhance the accuracy of the returned range. 240 * If it is not possible to return the range, because the field is not supported 241 * or for some other reason, an exception is thrown. 242 * <p> 243 * If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then the 244 * range of the day-of-week, from 1 to 7, will be returned. 245 * All other {@code ChronoField} instances will throw a {@code DateTimeException}. 246 * <p> 247 * If the field is not a {@code ChronoField}, then the result of this method 248 * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)} 249 * passing {@code this} as the argument. 250 * Whether the range can be obtained is determined by the field. 251 * 252 * @param field the field to query the range for, not null 253 * @return the range of valid values for the field, not null 254 * @throws DateTimeException if the range for the field cannot be obtained 255 */ 256 @Override range(TemporalField field)257 public ValueRange range(TemporalField field) { 258 if (field == DAY_OF_WEEK) { 259 return field.range(); 260 } else if (field instanceof ChronoField) { 261 throw new UnsupportedTemporalTypeException("Unsupported field: " + field); 262 } 263 return field.rangeRefinedBy(this); 264 } 265 266 /** 267 * Gets the value of the specified field from this day-of-week as an {@code int}. 268 * <p> 269 * This queries this day-of-week for the value for the specified field. 270 * The returned value will always be within the valid range of values for the field. 271 * If it is not possible to return the value, because the field is not supported 272 * or for some other reason, an exception is thrown. 273 * <p> 274 * If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then the 275 * value of the day-of-week, from 1 to 7, will be returned. 276 * All other {@code ChronoField} instances will throw a {@code DateTimeException}. 277 * <p> 278 * If the field is not a {@code ChronoField}, then the result of this method 279 * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} 280 * passing {@code this} as the argument. Whether the value can be obtained, 281 * and what the value represents, is determined by the field. 282 * 283 * @param field the field to get, not null 284 * @return the value for the field, within the valid range of values 285 * @throws DateTimeException if a value for the field cannot be obtained 286 * @throws DateTimeException if the range of valid values for the field exceeds an {@code int} 287 * @throws DateTimeException if the value is outside the range of valid values for the field 288 * @throws ArithmeticException if numeric overflow occurs 289 */ 290 @Override get(TemporalField field)291 public int get(TemporalField field) { 292 if (field == DAY_OF_WEEK) { 293 return getValue(); 294 } 295 return range(field).checkValidIntValue(getLong(field), field); 296 } 297 298 /** 299 * Gets the value of the specified field from this day-of-week as a {@code long}. 300 * <p> 301 * This queries this day-of-week for the value for the specified field. 302 * If it is not possible to return the value, because the field is not supported 303 * or for some other reason, an exception is thrown. 304 * <p> 305 * If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then the 306 * value of the day-of-week, from 1 to 7, will be returned. 307 * All other {@code ChronoField} instances will throw a {@code DateTimeException}. 308 * <p> 309 * If the field is not a {@code ChronoField}, then the result of this method 310 * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)} 311 * passing {@code this} as the argument. Whether the value can be obtained, 312 * and what the value represents, is determined by the field. 313 * 314 * @param field the field to get, not null 315 * @return the value for the field 316 * @throws DateTimeException if a value for the field cannot be obtained 317 * @throws ArithmeticException if numeric overflow occurs 318 */ 319 @Override getLong(TemporalField field)320 public long getLong(TemporalField field) { 321 if (field == DAY_OF_WEEK) { 322 return getValue(); 323 } else if (field instanceof ChronoField) { 324 throw new UnsupportedTemporalTypeException("Unsupported field: " + field); 325 } 326 return field.getFrom(this); 327 } 328 329 //----------------------------------------------------------------------- 330 /** 331 * Returns the day-of-week that is the specified number of days after this one. 332 * <p> 333 * The calculation rolls around the end of the week from Sunday to Monday. 334 * The specified period may be negative. 335 * <p> 336 * This instance is immutable and unaffected by this method call. 337 * 338 * @param days the days to add, positive or negative 339 * @return the resulting day-of-week, not null 340 */ plus(long days)341 public DayOfWeek plus(long days) { 342 int amount = (int) (days % 7); 343 return ENUMS[(ordinal() + (amount + 7)) % 7]; 344 } 345 346 /** 347 * Returns the day-of-week that is the specified number of days before this one. 348 * <p> 349 * The calculation rolls around the start of the year from Monday to Sunday. 350 * The specified period may be negative. 351 * <p> 352 * This instance is immutable and unaffected by this method call. 353 * 354 * @param days the days to subtract, positive or negative 355 * @return the resulting day-of-week, not null 356 */ minus(long days)357 public DayOfWeek minus(long days) { 358 return plus(-(days % 7)); 359 } 360 361 //----------------------------------------------------------------------- 362 /** 363 * Queries this day-of-week using the specified query. 364 * <p> 365 * This queries this day-of-week using the specified query strategy object. 366 * The {@code TemporalQuery} object defines the logic to be used to 367 * obtain the result. Read the documentation of the query to understand 368 * what the result of this method will be. 369 * <p> 370 * The result of this method is obtained by invoking the 371 * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the 372 * specified query passing {@code this} as the argument. 373 * 374 * @param <R> the type of the result 375 * @param query the query to invoke, not null 376 * @return the query result, null may be returned (defined by the query) 377 * @throws DateTimeException if unable to query (defined by the query) 378 * @throws ArithmeticException if numeric overflow occurs (defined by the query) 379 */ 380 @SuppressWarnings("unchecked") 381 @Override query(TemporalQuery<R> query)382 public <R> R query(TemporalQuery<R> query) { 383 if (query == TemporalQueries.precision()) { 384 return (R) DAYS; 385 } else if (query == TemporalQueries.localDate() || query == TemporalQueries.localTime() || query == TemporalQueries.chronology() || 386 query == TemporalQueries.zone() || query == TemporalQueries.zoneId() || query == TemporalQueries.offset()) { 387 return null; 388 } 389 return query.queryFrom(this); 390 } 391 392 /** 393 * Adjusts the specified temporal object to have this day-of-week. 394 * <p> 395 * This returns a temporal object of the same observable type as the input 396 * with the day-of-week changed to be the same as this. 397 * <p> 398 * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)} 399 * passing {@link ChronoField#DAY_OF_WEEK} as the field. 400 * Note that this adjusts forwards or backwards within a Monday to Sunday week. 401 * See {@link WeekFields#dayOfWeek} for localized week start days. 402 * See {@link TemporalAdjusters} for other adjusters 403 * with more control, such as {@code next(MONDAY)}. 404 * <p> 405 * In most cases, it is clearer to reverse the calling pattern by using 406 * {@link Temporal#with(TemporalAdjuster)}: 407 * <pre> 408 * // these two lines are equivalent, but the second approach is recommended 409 * temporal = thisDayOfWeek.adjustInto(temporal); 410 * temporal = temporal.with(thisDayOfWeek); 411 * </pre> 412 * <p> 413 * For example, given a date that is a Wednesday, the following are output: 414 * <pre> 415 * dateOnWed.with(MONDAY); // two days earlier 416 * dateOnWed.with(TUESDAY); // one day earlier 417 * dateOnWed.with(WEDNESDAY); // same date 418 * dateOnWed.with(THURSDAY); // one day later 419 * dateOnWed.with(FRIDAY); // two days later 420 * dateOnWed.with(SATURDAY); // three days later 421 * dateOnWed.with(SUNDAY); // four days later 422 * </pre> 423 * <p> 424 * This instance is immutable and unaffected by this method call. 425 * 426 * @param temporal the target object to be adjusted, not null 427 * @return the adjusted object, not null 428 * @throws DateTimeException if unable to make the adjustment 429 * @throws ArithmeticException if numeric overflow occurs 430 */ 431 @Override adjustInto(Temporal temporal)432 public Temporal adjustInto(Temporal temporal) { 433 return temporal.with(DAY_OF_WEEK, getValue()); 434 } 435 436 } 437