• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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