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;
  63 
  64 import static java.time.temporal.ChronoField.DAY_OF_WEEK;
  65 import static java.time.temporal.ChronoUnit.DAYS;
  66 
  67 import java.time.format.DateTimeFormatterBuilder;
  68 import java.time.format.TextStyle;
  69 import java.time.temporal.ChronoField;
  70 import java.time.temporal.Queries;
  71 import java.time.temporal.Temporal;
  72 import java.time.temporal.TemporalAccessor;
  73 import java.time.temporal.TemporalAdjuster;
  74 import java.time.temporal.TemporalField;
  75 import java.time.temporal.TemporalQuery;
  76 import java.time.temporal.ValueRange;
  77 import java.time.temporal.WeekFields;
  78 import java.util.Locale;
  79 
  80 /**
  81  * A day-of-week, such as 'Tuesday'.
  82  * <p>
  83  * {@code DayOfWeek} is an enum representing the 7 days of the week -
  84  * Monday, Tuesday, Wednesday, Thursday, Friday, Saturday and Sunday.
  85  * <p>
  86  * In addition to the textual enum name, each day-of-week has an {@code int} value.
  87  * The {@code int} value follows the ISO-8601 standard, from 1 (Monday) to 7 (Sunday).
  88  * It is recommended that applications use the enum rather than the {@code int} value
  89  * to ensure code clarity.
  90  * <p>
  91  * This enum provides access to the localized textual form of the day-of-week.
  92  * Some locales also assign different numeric values to the days, declaring
  93  * Sunday to have the value 1, however this class provides no support for this.
  94  * See {@link WeekFields} for localized week-numbering.
  95  * <p>
  96  * <b>Do not use {@code ordinal()} to obtain the numeric representation of {@code DayOfWeek}.
  97  * Use {@code getValue()} instead.</b>
  98  * <p>
  99  * This enum represents a common concept that is found in many calendar systems.
 100  * As such, this enum may be used by any calendar system that has the day-of-week
 101  * concept defined exactly equivalent to the ISO calendar system.
 102  *
 103  * <h3>Specification for implementors</h3>
 104  * This is an immutable and thread-safe enum.
 105  *
 106  * @since 1.8
 107  */
 108 public enum DayOfWeek implements TemporalAccessor, TemporalAdjuster {
 109 
 110     /**
 111      * The singleton instance for the day-of-week of Monday.
 112      * This has the numeric value of {@code 1}.
 113      */
 114     MONDAY,
 115     /**
 116      * The singleton instance for the day-of-week of Tuesday.
 117      * This has the numeric value of {@code 2}.
 118      */
 119     TUESDAY,
 120     /**
 121      * The singleton instance for the day-of-week of Wednesday.
 122      * This has the numeric value of {@code 3}.
 123      */
 124     WEDNESDAY,
 125     /**
 126      * The singleton instance for the day-of-week of Thursday.
 127      * This has the numeric value of {@code 4}.
 128      */
 129     THURSDAY,
 130     /**
 131      * The singleton instance for the day-of-week of Friday.
 132      * This has the numeric value of {@code 5}.
 133      */
 134     FRIDAY,
 135     /**
 136      * The singleton instance for the day-of-week of Saturday.
 137      * This has the numeric value of {@code 6}.
 138      */
 139     SATURDAY,
 140     /**
 141      * The singleton instance for the day-of-week of Sunday.
 142      * This has the numeric value of {@code 7}.
 143      */
 144     SUNDAY;
 145     /**
 146      * Private cache of all the constants.
 147      */
 148     private static final DayOfWeek[] ENUMS = DayOfWeek.values();
 149 
 150     //-----------------------------------------------------------------------
 151     /**
 152      * Obtains an instance of {@code DayOfWeek} from an {@code int} value.
 153      * <p>
 154      * {@code DayOfWeek} is an enum representing the 7 days of the week.
 155      * This factory allows the enum to be obtained from the {@code int} value.
 156      * The {@code int} value follows the ISO-8601 standard, from 1 (Monday) to 7 (Sunday).
 157      *
 158      * @param dayOfWeek  the day-of-week to represent, from 1 (Monday) to 7 (Sunday)
 159      * @return the day-of-week singleton, not null
 160      * @throws DateTimeException if the day-of-week is invalid
 161      */
 162     public static DayOfWeek of(int dayOfWeek) {
 163         if (dayOfWeek < 1 || dayOfWeek > 7) {
 164             throw new DateTimeException("Invalid value for DayOfWeek: " + dayOfWeek);
 165         }
 166         return ENUMS[dayOfWeek - 1];
 167     }
 168 
 169     //-----------------------------------------------------------------------
 170     /**
 171      * Obtains an instance of {@code DayOfWeek} from a temporal object.
 172      * <p>
 173      * This obtains a day-of-week based on the specified temporal.
 174      * A {@code TemporalAccessor} represents an arbitrary set of date and time information,
 175      * which this factory converts to an instance of {@code DayOfWeek}.
 176      * <p>
 177      * The conversion extracts the {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} field.
 178      * <p>
 179      * This method matches the signature of the functional interface {@link TemporalQuery}
 180      * allowing it to be used as a query via method reference, {@code DayOfWeek::from}.
 181      *
 182      * @param temporal  the temporal object to convert, not null
 183      * @return the day-of-week, not null
 184      * @throws DateTimeException if unable to convert to a {@code DayOfWeek}
 185      */
 186     public static DayOfWeek from(TemporalAccessor temporal) {
 187         if (temporal instanceof DayOfWeek) {
 188             return (DayOfWeek) temporal;
 189         }
 190         return of(temporal.get(DAY_OF_WEEK));
 191     }
 192 
 193     //-----------------------------------------------------------------------
 194     /**
 195      * Gets the day-of-week {@code int} value.
 196      * <p>
 197      * The values are numbered following the ISO-8601 standard, from 1 (Monday) to 7 (Sunday).
 198      * See {@link WeekFields#dayOfWeek} for localized week-numbering.
 199      *
 200      * @return the day-of-week, from 1 (Monday) to 7 (Sunday)
 201      */
 202     public int getValue() {
 203         return ordinal() + 1;
 204     }
 205 
 206     //-----------------------------------------------------------------------
 207     /**
 208      * Gets the textual representation, such as 'Mon' or 'Friday'.
 209      * <p>
 210      * This returns the textual name used to identify the day-of-week,
 211      * suitable for presentation to the user.
 212      * The parameters control the style of the returned text and the locale.
 213      * <p>
 214      * If no textual mapping is found then the {@link #getValue() numeric value} is returned.
 215      *
 216      * @param style  the length of the text required, not null
 217      * @param locale  the locale to use, not null
 218      * @return the text value of the day-of-week, not null
 219      */
 220     public String getDisplayName(TextStyle style, Locale locale) {
 221         return new DateTimeFormatterBuilder().appendText(DAY_OF_WEEK, style).toFormatter(locale).format(this);
 222     }
 223 
 224     //-----------------------------------------------------------------------
 225     /**
 226      * Checks if the specified field is supported.
 227      * <p>
 228      * This checks if this day-of-week can be queried for the specified field.
 229      * If false, then calling the {@link #range(TemporalField) range} and
 230      * {@link #get(TemporalField) get} methods will throw an exception.
 231      * <p>
 232      * If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then
 233      * this method returns true.
 234      * All other {@code ChronoField} instances will return false.
 235      * <p>
 236      * If the field is not a {@code ChronoField}, then the result of this method
 237      * is obtained by invoking {@code TemporalField.isSupportedBy(TemporalAccessor)}
 238      * passing {@code this} as the argument.
 239      * Whether the field is supported is determined by the field.
 240      *
 241      * @param field  the field to check, null returns false
 242      * @return true if the field is supported on this day-of-week, false if not
 243      */
 244     @Override
 245     public boolean isSupported(TemporalField field) {
 246         if (field instanceof ChronoField) {
 247             return field == DAY_OF_WEEK;
 248         }
 249         return field != null && field.isSupportedBy(this);
 250     }
 251 
 252     /**
 253      * Gets the range of valid values for the specified field.
 254      * <p>
 255      * The range object expresses the minimum and maximum valid values for a field.
 256      * This day-of-week is used to enhance the accuracy of the returned range.
 257      * If it is not possible to return the range, because the field is not supported
 258      * or for some other reason, an exception is thrown.
 259      * <p>
 260      * If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then the
 261      * range of the day-of-week, from 1 to 7, will be returned.
 262      * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
 263      * <p>
 264      * If the field is not a {@code ChronoField}, then the result of this method
 265      * is obtained by invoking {@code TemporalField.rangeRefinedBy(TemporalAccessor)}
 266      * passing {@code this} as the argument.
 267      * Whether the range can be obtained is determined by the field.
 268      *
 269      * @param field  the field to query the range for, not null
 270      * @return the range of valid values for the field, not null
 271      * @throws DateTimeException if the range for the field cannot be obtained
 272      */
 273     @Override
 274     public ValueRange range(TemporalField field) {
 275         if (field == DAY_OF_WEEK) {
 276             return field.range();
 277         }
 278         return TemporalAccessor.super.range(field);
 279     }
 280 
 281     /**
 282      * Gets the value of the specified field from this day-of-week as an {@code int}.
 283      * <p>
 284      * This queries this day-of-week for the value for the specified field.
 285      * The returned value will always be within the valid range of values for the 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.getFrom(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, within the valid range of values
 300      * @throws DateTimeException if a value for the field cannot be obtained
 301      * @throws ArithmeticException if numeric overflow occurs
 302      */
 303     @Override
 304     public int get(TemporalField field) {
 305         if (field == DAY_OF_WEEK) {
 306             return getValue();
 307         }
 308         return TemporalAccessor.super.get(field);
 309     }
 310 
 311     /**
 312      * Gets the value of the specified field from this day-of-week as a {@code long}.
 313      * <p>
 314      * This queries this day-of-week for the value for the specified field.
 315      * If it is not possible to return the value, because the field is not supported
 316      * or for some other reason, an exception is thrown.
 317      * <p>
 318      * If the field is {@link ChronoField#DAY_OF_WEEK DAY_OF_WEEK} then the
 319      * value of the day-of-week, from 1 to 7, will be returned.
 320      * All other {@code ChronoField} instances will throw a {@code DateTimeException}.
 321      * <p>
 322      * If the field is not a {@code ChronoField}, then the result of this method
 323      * is obtained by invoking {@code TemporalField.getFrom(TemporalAccessor)}
 324      * passing {@code this} as the argument. Whether the value can be obtained,
 325      * and what the value represents, is determined by the field.
 326      *
 327      * @param field  the field to get, not null
 328      * @return the value for the field
 329      * @throws DateTimeException if a value for the field cannot be obtained
 330      * @throws ArithmeticException if numeric overflow occurs
 331      */
 332     @Override
 333     public long getLong(TemporalField field) {
 334         if (field == DAY_OF_WEEK) {
 335             return getValue();
 336         } else if (field instanceof ChronoField) {
 337             throw new DateTimeException("Unsupported field: " + field.getName());
 338         }
 339         return field.getFrom(this);
 340     }
 341 
 342     //-----------------------------------------------------------------------
 343     /**
 344      * Returns the day-of-week that is the specified number of days after this one.
 345      * <p>
 346      * The calculation rolls around the end of the week from Sunday to Monday.
 347      * The specified period may be negative.
 348      * <p>
 349      * This instance is immutable and unaffected by this method call.
 350      *
 351      * @param days  the days to add, positive or negative
 352      * @return the resulting day-of-week, not null
 353      */
 354     public DayOfWeek plus(long days) {
 355         int amount = (int) (days % 7);
 356         return ENUMS[(ordinal() + (amount + 7)) % 7];
 357     }
 358 
 359     /**
 360      * Returns the day-of-week that is the specified number of days before this one.
 361      * <p>
 362      * The calculation rolls around the start of the year from Monday to Sunday.
 363      * The specified period may be negative.
 364      * <p>
 365      * This instance is immutable and unaffected by this method call.
 366      *
 367      * @param days  the days to subtract, positive or negative
 368      * @return the resulting day-of-week, not null
 369      */
 370     public DayOfWeek minus(long days) {
 371         return plus(-(days % 7));
 372     }
 373 
 374     //-----------------------------------------------------------------------
 375     /**
 376      * Queries this day-of-week using the specified query.
 377      * <p>
 378      * This queries this day-of-week using the specified query strategy object.
 379      * The {@code TemporalQuery} object defines the logic to be used to
 380      * obtain the result. Read the documentation of the query to understand
 381      * what the result of this method will be.
 382      * <p>
 383      * The result of this method is obtained by invoking the
 384      * {@link TemporalQuery#queryFrom(TemporalAccessor)} method on the
 385      * specified query passing {@code this} as the argument.
 386      *
 387      * @param <R> the type of the result
 388      * @param query  the query to invoke, not null
 389      * @return the query result, null may be returned (defined by the query)
 390      * @throws DateTimeException if unable to query (defined by the query)
 391      * @throws ArithmeticException if numeric overflow occurs (defined by the query)
 392      */
 393     @SuppressWarnings("unchecked")
 394     @Override
 395     public <R> R query(TemporalQuery<R> query) {
 396         if (query == Queries.precision()) {
 397             return (R) DAYS;
 398         }
 399         return TemporalAccessor.super.query(query);
 400     }
 401 
 402     /**
 403      * Adjusts the specified temporal object to have this day-of-week.
 404      * <p>
 405      * This returns a temporal object of the same observable type as the input
 406      * with the day-of-week changed to be the same as this.
 407      * <p>
 408      * The adjustment is equivalent to using {@link Temporal#with(TemporalField, long)}
 409      * passing {@link ChronoField#DAY_OF_WEEK} as the field.
 410      * Note that this adjusts forwards or backwards within a Monday to Sunday week.
 411      * See {@link WeekFields#dayOfWeek} for localized week start days.
 412      * See {@link java.time.temporal.Adjusters Adjusters} for other adjusters
 413      * with more control, such as {@code next(MONDAY)}.
 414      * <p>
 415      * In most cases, it is clearer to reverse the calling pattern by using
 416      * {@link Temporal#with(TemporalAdjuster)}:
 417      * <pre>
 418      *   // these two lines are equivalent, but the second approach is recommended
 419      *   temporal = thisDayOfWeek.adjustInto(temporal);
 420      *   temporal = temporal.with(thisDayOfWeek);
 421      * </pre>
 422      * <p>
 423      * For example, given a date that is a Wednesday, the following are output:
 424      * <pre>
 425      *   dateOnWed.with(MONDAY);     // two days earlier
 426      *   dateOnWed.with(TUESDAY);    // one day earlier
 427      *   dateOnWed.with(WEDNESDAY);  // same date
 428      *   dateOnWed.with(THURSDAY);   // one day later
 429      *   dateOnWed.with(FRIDAY);     // two days later
 430      *   dateOnWed.with(SATURDAY);   // three days later
 431      *   dateOnWed.with(SUNDAY);     // four days later
 432      * </pre>
 433      * <p>
 434      * This instance is immutable and unaffected by this method call.
 435      *
 436      * @param temporal  the target object to be adjusted, not null
 437      * @return the adjusted object, not null
 438      * @throws DateTimeException if unable to make the adjustment
 439      * @throws ArithmeticException if numeric overflow occurs
 440      */
 441     @Override
 442     public Temporal adjustInto(Temporal temporal) {
 443         return temporal.with(DAY_OF_WEEK, getValue());
 444     }
 445 
 446 }