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; 033 034import static org.threeten.bp.temporal.ChronoField.DAY_OF_WEEK; 035import static org.threeten.bp.temporal.ChronoUnit.DAYS; 036 037import java.util.Locale; 038 039import org.threeten.bp.format.DateTimeFormatterBuilder; 040import org.threeten.bp.format.TextStyle; 041import org.threeten.bp.temporal.ChronoField; 042import org.threeten.bp.temporal.Temporal; 043import org.threeten.bp.temporal.TemporalAccessor; 044import org.threeten.bp.temporal.TemporalAdjuster; 045import org.threeten.bp.temporal.TemporalField; 046import org.threeten.bp.temporal.TemporalQueries; 047import org.threeten.bp.temporal.TemporalQuery; 048import org.threeten.bp.temporal.ValueRange; 049import org.threeten.bp.temporal.WeekFields; 050 051/** 052 * A day-of-week, such as 'Tuesday'. 053 * <p> 054 * {@code DayOfWeek} is an enum representing the 7 days of the week - 055 * Monday, Tuesday, Wednesday, Thursday, Friday, Saturday and Sunday. 056 * <p> 057 * In addition to the textual enum name, each day-of-week has an {@code int} value. 058 * The {@code int} value follows the ISO-8601 standard, from 1 (Monday) to 7 (Sunday). 059 * It is recommended that applications use the enum rather than the {@code int} value 060 * to ensure code clarity. 061 * <p> 062 * This enum provides access to the localized textual form of the day-of-week. 063 * Some locales also assign different numeric values to the days, declaring 064 * Sunday to have the value 1, however this class provides no support for this. 065 * See {@link WeekFields} for localized week-numbering. 066 * <p> 067 * <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code DayOfWeek}. 068 * Use {@code getValue()} instead.</b> 069 * <p> 070 * This enum represents a common concept that is found in many calendar systems. 071 * As such, this enum may be used by any calendar system that has the day-of-week 072 * concept defined exactly equivalent to the ISO calendar system. 073 * 074 * <h3>Specification for implementors</h3> 075 * This is an immutable and thread-safe enum. 076 */ 077public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster { 078 079 /** 080 * The singleton instance for the day-of-week of Monday. 081 * This has the numeric value of {@code 1}. 082 */ 083 MONDAY, 084 /** 085 * The singleton instance for the day-of-week of Tuesday. 086 * This has the numeric value of {@code 2}. 087 */ 088 TUESDAY, 089 /** 090 * The singleton instance for the day-of-week of Wednesday. 091 * This has the numeric value of {@code 3}. 092 */ 093 WEDNESDAY, 094 /** 095 * The singleton instance for the day-of-week of Thursday. 096 * This has the numeric value of {@code 4}. 097 */ 098 THURSDAY, 099 /** 100 * The singleton instance for the day-of-week of Friday. 101 * This has the numeric value of {@code 5}. 102 */ 103 FRIDAY, 104 /** 105 * The singleton instance for the day-of-week of Saturday. 106 * This has the numeric value of {@code 6}. 107 */ 108 SATURDAY, 109 /** 110 * The singleton instance for the day-of-week of Sunday. 111 * This has the numeric value of {@code 7}. 112 */ 113 SUNDAY; 114 /** 115 * Private cache of all the constants. 116 */ 117 private static final DayOfWeek[] ENUMS = DayOfWeek.values(); 118 119 //----------------------------------------------------------------------- 120 /** 121 * Obtains an instance of {@code DayOfWeek} from an {@code int} value. 122 * <p> 123 * {@code DayOfWeek} is an enum representing the 7 days of the week. 124 * This factory allows the enum to be obtained from the {@code int} value. 125 * The {@code int} value follows the ISO-8601 standard, from 1 (Monday) to 7 (Sunday). 126 * 127 * @param dayOfWeek the day-of-week to represent, from 1 (Monday) to 7 (Sunday) 128 * @return the day-of-week singleton, not null 129 * @throws DateTimeException if the day-of-week is invalid 130 */ 131 public static DayOfWeek of(int dayOfWeek) { 132 if (dayOfWeek < 1 || dayOfWeek > 7) { 133 throw new DateTimeException("Invalid value for DayOfWeek: " + dayOfWeek); 134 } 135 return ENUMS[dayOfWeek - 1]; 136 } 137 138 //----------------------------------------------------------------------- 139 /** 140 * Obtains an instance of {@code DayOfWeek} from a temporal object. 141 * <p> 142 * A {@code TemporalAccessor} represents some form of date and time information. 143 * This factory converts the arbitrary temporal object to an instance of {@code DayOfWeek}. 144 * <p> 145 * The conversion extracts the {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} field. 146 * <p> 147 * This method matches the signature of the functional interface {@link TemporalQuery} 148 * allowing it to be used as a query via method reference, {@code DayOfWeek::from}. 149 * 150 * @param temporal the temporal object to convert, not null 151 * @return the day-of-week, not null 152 * @throws DateTimeException if unable to convert to a {@code DayOfWeek} 153 */ 154 public static DayOfWeek from(TemporalAccessor temporal) { 155 if (temporal instanceof DayOfWeek) { 156 return (DayOfWeek) temporal; 157 } 158 return of(temporal.get(DAY_OF_WEEK)); 159 } 160 161 //----------------------------------------------------------------------- 162 /** 163 * Gets the day-of-week {@code int} value. 164 * <p> 165 * The values are numbered following the ISO-8601 standard, from 1 (Monday) to 7 (Sunday). 166 * See {@link WeekFields#dayOfWeek} for localized week-numbering. 167 * 168 * @return the day-of-week, from 1 (Monday) to 7 (Sunday) 169 */ 170 public int getValue() { 171 return ordinal() + 1; 172 } 173 174 //----------------------------------------------------------------------- 175 /** 176 * Gets the textual representation, such as 'Mon' or 'Friday'. 177 * <p> 178 * This returns the textual name used to identify the day-of-week. 179 * The parameters control the length of the returned text and the locale. 180 * <p> 181 * If no textual mapping is found then the {@link #getValue() numeric value} is returned. 182 * 183 * @param style the length of the text required, not null 184 * @param locale the locale to use, not null 185 * @return the text value of the day-of-week, not null 186 */ 187 public String getText(TextStyle style, Locale locale) { 188 return new DateTimeFormatterBuilder().appendText(DAY_OF_WEEK, style).toFormatter(locale).print(this); 189 } 190 191 //----------------------------------------------------------------------- 192 /** 193 * Checks if the specified field is supported. 194 * <p> 195 * This checks if this day-of-week can be queried for the specified field. 196 * If false, then calling the {@link #range(TemporalField) range} and 197 * {@link #get(TemporalField) get} methods will throw an exception. 198 * <p> 199 * If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then 200 * this method returns true. 201 * All other {@code ChronoField} instances will return false. 202 * <p> 203 * If the field is not a {@code ChronoField}, then the result of this method 204 * is obtained by invoking {@code TemporalField.doIsSupported(TemporalAccessor)} 205 * passing {@code this} as the argument. 206 * Whether the field is supported is determined by the field. 207 * 208 * @param field the field to check, null returns false 209 * @return true if the field is supported on this day-of-week, false if not 210 */ 211 @Override 212 public boolean isSupported(TemporalField field) { 213 if (field instanceof ChronoField) { 214 return field == DAY_OF_WEEK; 215 } 216 return field != null && field.doIsSupported(this); 217 } 218 219 /** 220 * Gets the range of valid values for the specified field. 221 * <p> 222 * The range object expresses the minimum and maximum valid values for a field. 223 * This day-of-week is used to enhance the accuracy of the returned range. 224 * If it is not possible to return the range, because the field is not supported 225 * or for some other reason, an exception is thrown. 226 * <p> 227 * If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then the 228 * range of the day-of-week, from 1 to 7, will be returned. 229 * All other {@code ChronoField} instances will throw a {@code DateTimeException}. 230 * <p> 231 * If the field is not a {@code ChronoField}, then the result of this method 232 * is obtained by invoking {@code TemporalField.doRange(TemporalAccessor)} 233 * passing {@code this} as the argument. 234 * Whether the range can be obtained is determined by the field. 235 * 236 * @param field the field to query the range for, not null 237 * @return the range of valid values for the field, not null 238 * @throws DateTimeException if the range for the field cannot be obtained 239 */ 240 @Override 241 public ValueRange range(TemporalField field) { 242 if (field == DAY_OF_WEEK) { 243 return field.range(); 244 } else if (field instanceof ChronoField) { 245 throw new DateTimeException("Unsupported field: " + field.getName()); 246 } 247 return field.doRange(this); 248 } 249 250 /** 251 * Gets the value of the specified field from this day-of-week as an {@code int}. 252 * <p> 253 * This queries this day-of-week for the value for the specified field. 254 * The returned value will always be within the valid range of values for the field. 255 * If it is not possible to return the value, because the field is not supported 256 * or for some other reason, an exception is thrown. 257 * <p> 258 * If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then the 259 * value of the day-of-week, from 1 to 7, will be returned. 260 * All other {@code ChronoField} instances will throw a {@code DateTimeException}. 261 * <p> 262 * If the field is not a {@code ChronoField}, then the result of this method 263 * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} 264 * passing {@code this} as the argument. Whether the value can be obtained, 265 * and what the value represents, is determined by the field. 266 * 267 * @param field the field to get, not null 268 * @return the value for the field, within the valid range of values 269 * @throws DateTimeException if a value for the field cannot be obtained 270 * @throws DateTimeException if the range of valid values for the field exceeds an {@code int} 271 * @throws DateTimeException if the value is outside the range of valid values for the field 272 * @throws ArithmeticException if numeric overflow occurs 273 */ 274 @Override 275 public int get(TemporalField field) { 276 if (field == DAY_OF_WEEK) { 277 return getValue(); 278 } 279 return range(field).checkValidIntValue(getLong(field), field); 280 } 281 282 /** 283 * Gets the value of the specified field from this day-of-week as a {@code long}. 284 * <p> 285 * This queries this day-of-week for the value for the specified field. 286 * If it is not possible to return the value, because the field is not supported 287 * or for some other reason, an exception is thrown. 288 * <p> 289 * If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then the 290 * value of the day-of-week, from 1 to 7, will be returned. 291 * All other {@code ChronoField} instances will throw a {@code DateTimeException}. 292 * <p> 293 * If the field is not a {@code ChronoField}, then the result of this method 294 * is obtained by invoking {@code TemporalField.doGet(TemporalAccessor)} 295 * passing {@code this} as the argument. Whether the value can be obtained, 296 * and what the value represents, is determined by the field. 297 * 298 * @param field the field to get, not null 299 * @return the value for the field 300 * @throws DateTimeException if a value for the field cannot be obtained 301 * @throws ArithmeticException if numeric overflow occurs 302 */ 303 @Override 304 public long getLong(TemporalField field) { 305 if (field == DAY_OF_WEEK) { 306 return getValue(); 307 } else if (field instanceof ChronoField) { 308 throw new DateTimeException("Unsupported field: " + field.getName()); 309 } 310 return field.doGet(this); 311 } 312 313 //----------------------------------------------------------------------- 314 /** 315 * Returns the day-of-week that is the specified number of days after this one. 316 * <p> 317 * The calculation rolls around the end of the week from Sunday to Monday. 318 * The specified period may be negative. 319 * <p> 320 * This instance is immutable and unaffected by this method call. 321 * 322 * @param days the days to add, positive or negative 323 * @return the resulting day-of-week, not null 324 */ 325 public DayOfWeek plus(long days) { 326 int amount = (int) (days % 7); 327 return ENUMS[(ordinal() + (amount + 7)) % 7]; 328 } 329 330 /** 331 * Returns the day-of-week that is the specified number of days before this one. 332 * <p> 333 * The calculation rolls around the start of the year from Monday to Sunday. 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 subtract, positive or negative 339 * @return the resulting day-of-week, not null 340 */ 341 public DayOfWeek minus(long days) { 342 return plus(-(days % 7)); 343 } 344 345 //----------------------------------------------------------------------- 346 /** 347 * Queries this day-of-week using the specified query. 348 * <p> 349 * This queries this day-of-week using the specified query strategy object. 350 * The {@code TemporalQuery} object defines the logic to be used to 351 * obtain the result. Read the documentation of the query to understand 352 * what the result of this method will be. 353 * <p> 354 * The result of this method is obtained by invoking the 355 * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the 356 * specified query passing {@code this} as the argument. 357 * 358 * @param <R> the type of the result 359 * @param query the query to invoke, not null 360 * @return the query result, null may be returned (defined by the query) 361 * @throws DateTimeException if unable to query (defined by the query) 362 * @throws ArithmeticException if numeric overflow occurs (defined by the query) 363 */ 364 @SuppressWarnings("unchecked") 365 @Override 366 public <R> R query(TemporalQuery<R> query) { 367 if (query == TemporalQueries.precision()) { 368 return (R) DAYS; 369 } else if (query == TemporalQueries.zoneId() || query == TemporalQueries.chrono()) { 370 return null; 371 } 372 return query.queryFrom(this); 373 } 374 375 /** 376 * Adjusts the specified temporal object to have this day-of-week. 377 * <p> 378 * This returns a temporal object of the same observable type as the input 379 * with the day-of-week changed to be the same as this. 380 * <p> 381 * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)} 382 * passing {@link ChronoField#DAY_OF_WEEK} as the field. 383 * Note that this adjusts forwards or backwards within a Monday to Sunday week. 384 * See {@link WeekFields#dayOfWeek} for localized week start days. 385 * See {@link TemporalAdjusters} for other adjusters 386 * with more control, such as {@code next(MONDAY)}. 387 * <p> 388 * In most cases, it is clearer to reverse the calling pattern by using 389 * {@link Temporal#with(TemporalAdjuster)}: 390 * <pre> 391 * // these two lines are equivalent, but the second approach is recommended 392 * temporal = thisDayOfWeek.adjustInto(temporal); 393 * temporal = temporal.with(thisDayOfWeek); 394 * </pre> 395 * <p> 396 * For example, given a date that is a Wednesday, the following are output: 397 * <pre> 398 * dateOnWed.with(MONDAY); // two days earlier 399 * dateOnWed.with(TUESDAY); // one day earlier 400 * dateOnWed.with(WEDNESDAY); // same date 401 * dateOnWed.with(THURSDAY); // one day later 402 * dateOnWed.with(FRIDAY); // two days later 403 * dateOnWed.with(SATURDAY); // three days later 404 * dateOnWed.with(SUNDAY); // four days later 405 * </pre> 406 * <p> 407 * This instance is immutable and unaffected by this method call. 408 * 409 * @param temporal the target object to be adjusted, not null 410 * @return the adjusted object, not null 411 * @throws DateTimeException if unable to make the adjustment 412 * @throws ArithmeticException if numeric overflow occurs 413 */ 414 @Override 415 public Temporal adjustInto(Temporal temporal) { 416 return temporal.with(DAY_OF_WEEK, getValue()); 417 } 418 419}