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