1c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer/*
2c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
3c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *
5c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * This code is free software; you can redistribute it and/or modify it
6c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * under the terms of the GNU General Public License version 2 only, as
7c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * published by the Free Software Foundation.  Oracle designates this
8c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * particular file as subject to the "Classpath" exception as provided
9c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * by Oracle in the LICENSE file that accompanied this code.
10c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *
11c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * This code is distributed in the hope that it will be useful, but WITHOUT
12c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * version 2 for more details (a copy is included in the LICENSE file that
15c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * accompanied this code).
16c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *
17c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * You should have received a copy of the GNU General Public License version
18c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * 2 along with this work; if not, write to the Free Software Foundation,
19c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *
21c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * or visit www.oracle.com if you need additional information or have any
23c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * questions.
24c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer */
25c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
26c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer/*
27c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * This file is available under and governed by the GNU General Public
28c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * License version 2 only, as published by the Free Software Foundation.
29c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * However, the following notice accompanied the original version of this
30c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * file:
31c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *
32c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * Copyright (c) 2011-2012, Stephen Colebourne & Michael Nascimento Santos
33c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *
34c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * All rights reserved.
35c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *
36c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * Redistribution and use in source and binary forms, with or without
37c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * modification, are permitted provided that the following conditions are met:
38c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *
39c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *  * Redistributions of source code must retain the above copyright notice,
40c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *    this list of conditions and the following disclaimer.
41c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *
42c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *  * Redistributions in binary form must reproduce the above copyright notice,
43c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *    this list of conditions and the following disclaimer in the documentation
44c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *    and/or other materials provided with the distribution.
45c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *
46c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *  * Neither the name of JSR-310 nor the names of its contributors
47c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *    may be used to endorse or promote products derived from this software
48c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *    without specific prior written permission.
49c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *
50c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
51c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
52c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
53c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
54c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
55c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
56c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
57c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
58c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
59c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
60c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
61c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer */
62c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerpackage java.time.temporal;
63c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
64d7928577b0cc656c1c6da16bfe281541fdd435eeJoachim Sauerimport android.icu.text.DateTimePatternGenerator;
65d7928577b0cc656c1c6da16bfe281541fdd435eeJoachim Sauerimport android.icu.util.Calendar;
66d7928577b0cc656c1c6da16bfe281541fdd435eeJoachim Sauerimport android.icu.util.ULocale;
67d7928577b0cc656c1c6da16bfe281541fdd435eeJoachim Sauer
68c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerimport static java.time.temporal.ChronoField.DAY_OF_MONTH;
69c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerimport static java.time.temporal.ChronoField.DAY_OF_WEEK;
70c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerimport static java.time.temporal.ChronoField.DAY_OF_YEAR;
71c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerimport static java.time.temporal.ChronoField.MONTH_OF_YEAR;
72c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerimport static java.time.temporal.ChronoField.YEAR;
73c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerimport static java.time.temporal.ChronoUnit.DAYS;
74c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerimport static java.time.temporal.ChronoUnit.FOREVER;
75c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerimport static java.time.temporal.ChronoUnit.MONTHS;
76c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerimport static java.time.temporal.ChronoUnit.WEEKS;
77c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerimport static java.time.temporal.ChronoUnit.YEARS;
78c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
79c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerimport java.io.IOException;
80c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerimport java.io.InvalidObjectException;
81c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerimport java.io.ObjectInputStream;
82c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerimport java.io.Serializable;
83c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerimport java.time.DateTimeException;
84c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerimport java.time.DayOfWeek;
85c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerimport java.time.chrono.ChronoLocalDate;
86c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerimport java.time.chrono.Chronology;
87c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerimport java.time.format.ResolverStyle;
88c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerimport java.util.Locale;
89c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerimport java.util.Map;
90c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerimport java.util.Objects;
91c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerimport java.util.concurrent.ConcurrentHashMap;
92c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerimport java.util.concurrent.ConcurrentMap;
93c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
94c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer/**
95c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * Localized definitions of the day-of-week, week-of-month and week-of-year fields.
96c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * <p>
97c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * A standard week is seven days long, but cultures have different definitions for some
98c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * other aspects of a week. This class represents the definition of the week, for the
99c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * purpose of providing {@link TemporalField} instances.
100c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * <p>
101c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * WeekFields provides five fields,
102c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * {@link #dayOfWeek()}, {@link #weekOfMonth()}, {@link #weekOfYear()},
103c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * {@link #weekOfWeekBasedYear()}, and {@link #weekBasedYear()}
104c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * that provide access to the values from any {@linkplain Temporal temporal object}.
105c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * <p>
106c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * The computations for day-of-week, week-of-month, and week-of-year are based
107c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * on the  {@linkplain ChronoField#YEAR proleptic-year},
108c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * {@linkplain ChronoField#MONTH_OF_YEAR month-of-year},
109c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * {@linkplain ChronoField#DAY_OF_MONTH day-of-month}, and
110c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * {@linkplain ChronoField#DAY_OF_WEEK ISO day-of-week} which are based on the
111c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * {@linkplain ChronoField#EPOCH_DAY epoch-day} and the chronology.
112c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * The values may not be aligned with the {@linkplain ChronoField#YEAR_OF_ERA year-of-Era}
113c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * depending on the Chronology.
114c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * <p>A week is defined by:
115c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * <ul>
116c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * <li>The first day-of-week.
117c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * For example, the ISO-8601 standard considers Monday to be the first day-of-week.
118c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * <li>The minimal number of days in the first week.
119c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * For example, the ISO-8601 standard counts the first week as needing at least 4 days.
120c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * </ul>
121c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * Together these two values allow a year or month to be divided into weeks.
122c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *
123c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * <h3>Week of Month</h3>
124c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * One field is used: week-of-month.
125c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * The calculation ensures that weeks never overlap a month boundary.
126c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * The month is divided into periods where each period starts on the defined first day-of-week.
127c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * The earliest period is referred to as week 0 if it has less than the minimal number of days
128c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * and week 1 if it has at least the minimal number of days.
129c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *
130c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * <table cellpadding="0" cellspacing="3" border="0" style="text-align: left; width: 50%;">
131c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * <caption>Examples of WeekFields</caption>
132c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * <tr><th>Date</th><td>Day-of-week</td>
133c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *  <td>First day: Monday<br>Minimal days: 4</td><td>First day: Monday<br>Minimal days: 5</td></tr>
134c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * <tr><th>2008-12-31</th><td>Wednesday</td>
135c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *  <td>Week 5 of December 2008</td><td>Week 5 of December 2008</td></tr>
136c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * <tr><th>2009-01-01</th><td>Thursday</td>
137c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *  <td>Week 1 of January 2009</td><td>Week 0 of January 2009</td></tr>
138c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * <tr><th>2009-01-04</th><td>Sunday</td>
139c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *  <td>Week 1 of January 2009</td><td>Week 0 of January 2009</td></tr>
140c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * <tr><th>2009-01-05</th><td>Monday</td>
141c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *  <td>Week 2 of January 2009</td><td>Week 1 of January 2009</td></tr>
142c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * </table>
143c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *
144c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * <h3>Week of Year</h3>
145c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * One field is used: week-of-year.
146c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * The calculation ensures that weeks never overlap a year boundary.
147c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * The year is divided into periods where each period starts on the defined first day-of-week.
148c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * The earliest period is referred to as week 0 if it has less than the minimal number of days
149c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * and week 1 if it has at least the minimal number of days.
150c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *
151c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * <h3>Week Based Year</h3>
152c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * Two fields are used for week-based-year, one for the
153c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * {@link #weekOfWeekBasedYear() week-of-week-based-year} and one for
154c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * {@link #weekBasedYear() week-based-year}.  In a week-based-year, each week
155c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * belongs to only a single year.  Week 1 of a year is the first week that
156c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * starts on the first day-of-week and has at least the minimum number of days.
157c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * The first and last weeks of a year may contain days from the
158c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * previous calendar year or next calendar year respectively.
159c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *
160c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * <table cellpadding="0" cellspacing="3" border="0" style="text-align: left; width: 50%;">
161c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * <caption>Examples of WeekFields for week-based-year</caption>
162c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * <tr><th>Date</th><td>Day-of-week</td>
163c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *  <td>First day: Monday<br>Minimal days: 4</td><td>First day: Monday<br>Minimal days: 5</td></tr>
164c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * <tr><th>2008-12-31</th><td>Wednesday</td>
165c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *  <td>Week 1 of 2009</td><td>Week 53 of 2008</td></tr>
166c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * <tr><th>2009-01-01</th><td>Thursday</td>
167c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *  <td>Week 1 of 2009</td><td>Week 53 of 2008</td></tr>
168c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * <tr><th>2009-01-04</th><td>Sunday</td>
169c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *  <td>Week 1 of 2009</td><td>Week 53 of 2008</td></tr>
170c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * <tr><th>2009-01-05</th><td>Monday</td>
171c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *  <td>Week 2 of 2009</td><td>Week 1 of 2009</td></tr>
172c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * </table>
173c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *
174c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * @implSpec
175c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * This class is immutable and thread-safe.
176c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer *
177c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer * @since 1.8
178c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer */
179c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauerpublic final class WeekFields implements Serializable {
180c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    // implementation notes
181c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    // querying week-of-month or week-of-year should return the week value bound within the month/year
182c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    // however, setting the week value should be lenient (use plus/minus weeks)
183c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    // allow week-of-month outer range [0 to 6]
184c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    // allow week-of-year outer range [0 to 54]
185c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    // this is because callers shouldn't be expected to know the details of validity
186c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
187c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
188c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * The cache of rules by firstDayOfWeek plus minimalDays.
189c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Initialized first to be available for definition of ISO, etc.
190c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
191c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    private static final ConcurrentMap<String, WeekFields> CACHE = new ConcurrentHashMap<>(4, 0.75f, 2);
192c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
193c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
194c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * The ISO-8601 definition, where a week starts on Monday and the first week
195c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * has a minimum of 4 days.
196c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
197c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * The ISO-8601 standard defines a calendar system based on weeks.
198c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * It uses the week-based-year and week-of-week-based-year concepts to split
199c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * up the passage of days instead of the standard year/month/day.
200c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
201c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Note that the first week may start in the previous calendar year.
202c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Note also that the first few days of a calendar year may be in the
203c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * week-based-year corresponding to the previous calendar year.
204c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
205c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    public static final WeekFields ISO = new WeekFields(DayOfWeek.MONDAY, 4);
206c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
207c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
208c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * The common definition of a week that starts on Sunday and the first week
209c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * has a minimum of 1 day.
210c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
211c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Defined as starting on Sunday and with a minimum of 1 day in the month.
212c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * This week definition is in use in the US and other European countries.
213c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
214c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    public static final WeekFields SUNDAY_START = WeekFields.of(DayOfWeek.SUNDAY, 1);
215c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
216c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
217c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * The unit that represents week-based-years for the purpose of addition and subtraction.
218c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
219c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * This allows a number of week-based-years to be added to, or subtracted from, a date.
220c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * The unit is equal to either 52 or 53 weeks.
221c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * The estimated duration of a week-based-year is the same as that of a standard ISO
222c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * year at {@code 365.2425 Days}.
223c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
224c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * The rules for addition add the number of week-based-years to the existing value
225c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * for the week-based-year field retaining the week-of-week-based-year
226c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * and day-of-week, unless the week number it too large for the target year.
227c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * In that case, the week is set to the last week of the year
228c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * with the same day-of-week.
229c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
230c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * This unit is an immutable and thread-safe singleton.
231c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
232c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    public static final TemporalUnit WEEK_BASED_YEARS = IsoFields.WEEK_BASED_YEARS;
233c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
234c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
235c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Serialization version.
236c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
237c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    private static final long serialVersionUID = -1177360819670808121L;
238c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
239c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
240c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * The first day-of-week.
241c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
242c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    private final DayOfWeek firstDayOfWeek;
243c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
244c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * The minimal number of days in the first week.
245c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
246c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    private final int minimalDays;
247c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
248c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * The field used to access the computed DayOfWeek.
249c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
250c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    private final transient TemporalField dayOfWeek = ComputedDayOfField.ofDayOfWeekField(this);
251c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
252c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * The field used to access the computed WeekOfMonth.
253c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
254c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    private final transient TemporalField weekOfMonth = ComputedDayOfField.ofWeekOfMonthField(this);
255c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
256c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * The field used to access the computed WeekOfYear.
257c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
258c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    private final transient TemporalField weekOfYear = ComputedDayOfField.ofWeekOfYearField(this);
259c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
260c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * The field that represents the week-of-week-based-year.
261c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
262c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * This field allows the week of the week-based-year value to be queried and set.
263c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
264c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * This unit is an immutable and thread-safe singleton.
265c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
266c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    private final transient TemporalField weekOfWeekBasedYear = ComputedDayOfField.ofWeekOfWeekBasedYearField(this);
267c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
268c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * The field that represents the week-based-year.
269c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
270c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * This field allows the week-based-year value to be queried and set.
271c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
272c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * This unit is an immutable and thread-safe singleton.
273c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
274c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    private final transient TemporalField weekBasedYear = ComputedDayOfField.ofWeekBasedYearField(this);
275c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
276c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    //-----------------------------------------------------------------------
277c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
278c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Obtains an instance of {@code WeekFields} appropriate for a locale.
279c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
280c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * This will look up appropriate values from the provider of localization data.
281c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     *
282c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @param locale  the locale to use, not null
283c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @return the week-definition, not null
284c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
285c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    public static WeekFields of(Locale locale) {
286c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        Objects.requireNonNull(locale, "locale");
2876975f84c2ed72e1e26d20190b6f318718c849008Tobias Thierer        // Android-changed: get Week data from ICU4J
288d7928577b0cc656c1c6da16bfe281541fdd435eeJoachim Sauer        ULocale ulocale = ULocale.forLocale(locale);
289d7928577b0cc656c1c6da16bfe281541fdd435eeJoachim Sauer        String region = ULocale.getRegionForSupplementalData(ulocale, /* inferRegion */ true);
290d7928577b0cc656c1c6da16bfe281541fdd435eeJoachim Sauer        Calendar.WeekData weekData = Calendar.getWeekDataForRegion(region);
291d7928577b0cc656c1c6da16bfe281541fdd435eeJoachim Sauer        DayOfWeek dow = DayOfWeek.SUNDAY.plus(weekData.firstDayOfWeek - 1);
292d7928577b0cc656c1c6da16bfe281541fdd435eeJoachim Sauer        return WeekFields.of(dow, weekData.minimalDaysInFirstWeek);
293c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    }
294c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
295c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
296c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Obtains an instance of {@code WeekFields} from the first day-of-week and minimal days.
297c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
298c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * The first day-of-week defines the ISO {@code DayOfWeek} that is day 1 of the week.
299c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * The minimal number of days in the first week defines how many days must be present
300c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * in a month or year, starting from the first day-of-week, before the week is counted
301c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * as the first week. A value of 1 will count the first day of the month or year as part
302c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * of the first week, whereas a value of 7 will require the whole seven days to be in
303c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * the new month or year.
304c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
305c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * WeekFields instances are singletons; for each unique combination
306c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * of {@code firstDayOfWeek} and {@code minimalDaysInFirstWeek} the
307c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * the same instance will be returned.
308c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     *
309c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @param firstDayOfWeek  the first day of the week, not null
310c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @param minimalDaysInFirstWeek  the minimal number of days in the first week, from 1 to 7
311c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @return the week-definition, not null
312c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @throws IllegalArgumentException if the minimal days value is less than one
313c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     *      or greater than 7
314c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
315c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    public static WeekFields of(DayOfWeek firstDayOfWeek, int minimalDaysInFirstWeek) {
316c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        String key = firstDayOfWeek.toString() + minimalDaysInFirstWeek;
317c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        WeekFields rules = CACHE.get(key);
318c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        if (rules == null) {
319c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            rules = new WeekFields(firstDayOfWeek, minimalDaysInFirstWeek);
320c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            CACHE.putIfAbsent(key, rules);
321c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            rules = CACHE.get(key);
322c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
323c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        return rules;
324c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    }
325c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
326c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    //-----------------------------------------------------------------------
327c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
328c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Creates an instance of the definition.
329c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     *
330c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @param firstDayOfWeek  the first day of the week, not null
331c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @param minimalDaysInFirstWeek  the minimal number of days in the first week, from 1 to 7
332c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @throws IllegalArgumentException if the minimal days value is invalid
333c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
334c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    private WeekFields(DayOfWeek firstDayOfWeek, int minimalDaysInFirstWeek) {
335c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        Objects.requireNonNull(firstDayOfWeek, "firstDayOfWeek");
336c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        if (minimalDaysInFirstWeek < 1 || minimalDaysInFirstWeek > 7) {
337c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            throw new IllegalArgumentException("Minimal number of days is invalid");
338c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
339c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        this.firstDayOfWeek = firstDayOfWeek;
340c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        this.minimalDays = minimalDaysInFirstWeek;
341c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    }
342c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
343c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    //-----------------------------------------------------------------------
344c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
345c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Restore the state of a WeekFields from the stream.
346c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Check that the values are valid.
347c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     *
348c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @param s the stream to read
349c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @throws InvalidObjectException if the serialized object has an invalid
350c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     *     value for firstDayOfWeek or minimalDays.
351c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @throws ClassNotFoundException if a class cannot be resolved
352c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
353c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    private void readObject(ObjectInputStream s)
354c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         throws IOException, ClassNotFoundException, InvalidObjectException
355c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    {
356c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        s.defaultReadObject();
357c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        if (firstDayOfWeek == null) {
358c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            throw new InvalidObjectException("firstDayOfWeek is null");
359c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
360c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
361c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        if (minimalDays < 1 || minimalDays > 7) {
362c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            throw new InvalidObjectException("Minimal number of days is invalid");
363c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
364c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    }
365c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
366c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
367c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Return the singleton WeekFields associated with the
368c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * {@code firstDayOfWeek} and {@code minimalDays}.
369c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @return the singleton WeekFields for the firstDayOfWeek and minimalDays.
370c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @throws InvalidObjectException if the serialized object has invalid
371c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     *     values for firstDayOfWeek or minimalDays.
372c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
373c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    private Object readResolve() throws InvalidObjectException {
374c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        try {
375c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return WeekFields.of(firstDayOfWeek, minimalDays);
376c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        } catch (IllegalArgumentException iae) {
377c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            throw new InvalidObjectException("Invalid serialized WeekFields: " + iae.getMessage());
378c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
379c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    }
380c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
381c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    //-----------------------------------------------------------------------
382c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
383c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Gets the first day-of-week.
384c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
385c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * The first day-of-week varies by culture.
386c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * For example, the US uses Sunday, while France and the ISO-8601 standard use Monday.
387c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * This method returns the first day using the standard {@code DayOfWeek} enum.
388c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     *
389c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @return the first day-of-week, not null
390c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
391c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    public DayOfWeek getFirstDayOfWeek() {
392c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        return firstDayOfWeek;
393c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    }
394c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
395c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
396c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Gets the minimal number of days in the first week.
397c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
398c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * The number of days considered to define the first week of a month or year
399c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * varies by culture.
400c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * For example, the ISO-8601 requires 4 days (more than half a week) to
401c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * be present before counting the first week.
402c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     *
403c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @return the minimal number of days in the first week of a month or year, from 1 to 7
404c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
405c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    public int getMinimalDaysInFirstWeek() {
406c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        return minimalDays;
407c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    }
408c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
409c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    //-----------------------------------------------------------------------
410c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
411c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Returns a field to access the day of week based on this {@code WeekFields}.
412c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
413c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * This is similar to {@link ChronoField#DAY_OF_WEEK} but uses values for
414c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * the day-of-week based on this {@code WeekFields}.
415c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * The days are numbered from 1 to 7 where the
416c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * {@link #getFirstDayOfWeek() first day-of-week} is assigned the value 1.
417c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
418c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * For example, if the first day-of-week is Sunday, then that will have the
419c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * value 1, with other days ranging from Monday as 2 to Saturday as 7.
420c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
421c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * In the resolving phase of parsing, a localized day-of-week will be converted
422c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * to a standardized {@code ChronoField} day-of-week.
423c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * The day-of-week must be in the valid range 1 to 7.
424c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Other fields in this class build dates using the standardized day-of-week.
425c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     *
426c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @return a field providing access to the day-of-week with localized numbering, not null
427c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
428c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    public TemporalField dayOfWeek() {
429c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        return dayOfWeek;
430c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    }
431c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
432c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
433c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Returns a field to access the week of month based on this {@code WeekFields}.
434c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
435c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * This represents the concept of the count of weeks within the month where weeks
436c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * start on a fixed day-of-week, such as Monday.
437c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * This field is typically used with {@link WeekFields#dayOfWeek()}.
438c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
439c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Week one (1) is the week starting on the {@link WeekFields#getFirstDayOfWeek}
440c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * where there are at least {@link WeekFields#getMinimalDaysInFirstWeek()} days in the month.
441c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Thus, week one may start up to {@code minDays} days before the start of the month.
442c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * If the first week starts after the start of the month then the period before is week zero (0).
443c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
444c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * For example:<br>
445c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * - if the 1st day of the month is a Monday, week one starts on the 1st and there is no week zero<br>
446c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * - if the 2nd day of the month is a Monday, week one starts on the 2nd and the 1st is in week zero<br>
447c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * - if the 4th day of the month is a Monday, week one starts on the 4th and the 1st to 3rd is in week zero<br>
448c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * - if the 5th day of the month is a Monday, week two starts on the 5th and the 1st to 4th is in week one<br>
449c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
450c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * This field can be used with any calendar system.
451c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
452c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * In the resolving phase of parsing, a date can be created from a year,
453c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * week-of-month, month-of-year and day-of-week.
454c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
455c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * In {@linkplain ResolverStyle#STRICT strict mode}, all four fields are
456c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * validated against their range of valid values. The week-of-month field
457c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * is validated to ensure that the resulting month is the month requested.
458c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
459c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * In {@linkplain ResolverStyle#SMART smart mode}, all four fields are
460c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * validated against their range of valid values. The week-of-month field
461c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * is validated from 0 to 6, meaning that the resulting date can be in a
462c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * different month to that specified.
463c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
464c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * In {@linkplain ResolverStyle#LENIENT lenient mode}, the year and day-of-week
465c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * are validated against the range of valid values. The resulting date is calculated
466c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * equivalent to the following four stage approach.
467c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * First, create a date on the first day of the first week of January in the requested year.
468c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Then take the month-of-year, subtract one, and add the amount in months to the date.
469c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Then take the week-of-month, subtract one, and add the amount in weeks to the date.
470c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Finally, adjust to the correct day-of-week within the localized week.
471c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     *
472c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @return a field providing access to the week-of-month, not null
473c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
474c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    public TemporalField weekOfMonth() {
475c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        return weekOfMonth;
476c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    }
477c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
478c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
479c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Returns a field to access the week of year based on this {@code WeekFields}.
480c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
481c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * This represents the concept of the count of weeks within the year where weeks
482c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * start on a fixed day-of-week, such as Monday.
483c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * This field is typically used with {@link WeekFields#dayOfWeek()}.
484c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
485c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Week one(1) is the week starting on the {@link WeekFields#getFirstDayOfWeek}
486c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * where there are at least {@link WeekFields#getMinimalDaysInFirstWeek()} days in the year.
487c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Thus, week one may start up to {@code minDays} days before the start of the year.
488c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * If the first week starts after the start of the year then the period before is week zero (0).
489c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
490c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * For example:<br>
491c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * - if the 1st day of the year is a Monday, week one starts on the 1st and there is no week zero<br>
492c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * - if the 2nd day of the year is a Monday, week one starts on the 2nd and the 1st is in week zero<br>
493c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * - if the 4th day of the year is a Monday, week one starts on the 4th and the 1st to 3rd is in week zero<br>
494c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * - if the 5th day of the year is a Monday, week two starts on the 5th and the 1st to 4th is in week one<br>
495c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
496c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * This field can be used with any calendar system.
497c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
498c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * In the resolving phase of parsing, a date can be created from a year,
499c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * week-of-year and day-of-week.
500c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
501c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * In {@linkplain ResolverStyle#STRICT strict mode}, all three fields are
502c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * validated against their range of valid values. The week-of-year field
503c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * is validated to ensure that the resulting year is the year requested.
504c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
505c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * In {@linkplain ResolverStyle#SMART smart mode}, all three fields are
506c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * validated against their range of valid values. The week-of-year field
507c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * is validated from 0 to 54, meaning that the resulting date can be in a
508c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * different year to that specified.
509c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
510c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * In {@linkplain ResolverStyle#LENIENT lenient mode}, the year and day-of-week
511c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * are validated against the range of valid values. The resulting date is calculated
512c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * equivalent to the following three stage approach.
513c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * First, create a date on the first day of the first week in the requested year.
514c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Then take the week-of-year, subtract one, and add the amount in weeks to the date.
515c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Finally, adjust to the correct day-of-week within the localized week.
516c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     *
517c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @return a field providing access to the week-of-year, not null
518c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
519c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    public TemporalField weekOfYear() {
520c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        return weekOfYear;
521c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    }
522c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
523c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
524c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Returns a field to access the week of a week-based-year based on this {@code WeekFields}.
525c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
526c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * This represents the concept of the count of weeks within the year where weeks
527c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * start on a fixed day-of-week, such as Monday and each week belongs to exactly one year.
528c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * This field is typically used with {@link WeekFields#dayOfWeek()} and
529c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * {@link WeekFields#weekBasedYear()}.
530c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
531c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Week one(1) is the week starting on the {@link WeekFields#getFirstDayOfWeek}
532c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * where there are at least {@link WeekFields#getMinimalDaysInFirstWeek()} days in the year.
533c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * If the first week starts after the start of the year then the period before
534c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * is in the last week of the previous year.
535c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
536c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * For example:<br>
537c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * - if the 1st day of the year is a Monday, week one starts on the 1st<br>
538c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * - if the 2nd day of the year is a Monday, week one starts on the 2nd and
539c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     *   the 1st is in the last week of the previous year<br>
540c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * - if the 4th day of the year is a Monday, week one starts on the 4th and
541c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     *   the 1st to 3rd is in the last week of the previous year<br>
542c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * - if the 5th day of the year is a Monday, week two starts on the 5th and
543c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     *   the 1st to 4th is in week one<br>
544c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
545c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * This field can be used with any calendar system.
546c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
547c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * In the resolving phase of parsing, a date can be created from a week-based-year,
548c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * week-of-year and day-of-week.
549c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
550c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * In {@linkplain ResolverStyle#STRICT strict mode}, all three fields are
551c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * validated against their range of valid values. The week-of-year field
552c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * is validated to ensure that the resulting week-based-year is the
553c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * week-based-year requested.
554c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
555c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * In {@linkplain ResolverStyle#SMART smart mode}, all three fields are
556c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * validated against their range of valid values. The week-of-week-based-year field
557c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * is validated from 1 to 53, meaning that the resulting date can be in the
558c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * following week-based-year to that specified.
559c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
560c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * In {@linkplain ResolverStyle#LENIENT lenient mode}, the year and day-of-week
561c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * are validated against the range of valid values. The resulting date is calculated
562c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * equivalent to the following three stage approach.
563c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * First, create a date on the first day of the first week in the requested week-based-year.
564c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Then take the week-of-week-based-year, subtract one, and add the amount in weeks to the date.
565c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Finally, adjust to the correct day-of-week within the localized week.
566c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     *
567c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @return a field providing access to the week-of-week-based-year, not null
568c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
569c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    public TemporalField weekOfWeekBasedYear() {
570c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        return weekOfWeekBasedYear;
571c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    }
572c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
573c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
574c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Returns a field to access the year of a week-based-year based on this {@code WeekFields}.
575c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
576c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * This represents the concept of the year where weeks start on a fixed day-of-week,
577c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * such as Monday and each week belongs to exactly one year.
578c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * This field is typically used with {@link WeekFields#dayOfWeek()} and
579c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * {@link WeekFields#weekOfWeekBasedYear()}.
580c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
581c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Week one(1) is the week starting on the {@link WeekFields#getFirstDayOfWeek}
582c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * where there are at least {@link WeekFields#getMinimalDaysInFirstWeek()} days in the year.
583c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Thus, week one may start before the start of the year.
584c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * If the first week starts after the start of the year then the period before
585c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * is in the last week of the previous year.
586c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
587c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * This field can be used with any calendar system.
588c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
589c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * In the resolving phase of parsing, a date can be created from a week-based-year,
590c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * week-of-year and day-of-week.
591c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
592c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * In {@linkplain ResolverStyle#STRICT strict mode}, all three fields are
593c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * validated against their range of valid values. The week-of-year field
594c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * is validated to ensure that the resulting week-based-year is the
595c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * week-based-year requested.
596c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
597c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * In {@linkplain ResolverStyle#SMART smart mode}, all three fields are
598c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * validated against their range of valid values. The week-of-week-based-year field
599c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * is validated from 1 to 53, meaning that the resulting date can be in the
600c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * following week-based-year to that specified.
601c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
602c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * In {@linkplain ResolverStyle#LENIENT lenient mode}, the year and day-of-week
603c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * are validated against the range of valid values. The resulting date is calculated
604c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * equivalent to the following three stage approach.
605c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * First, create a date on the first day of the first week in the requested week-based-year.
606c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Then take the week-of-week-based-year, subtract one, and add the amount in weeks to the date.
607c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Finally, adjust to the correct day-of-week within the localized week.
608c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     *
609c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @return a field providing access to the week-based-year, not null
610c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
611c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    public TemporalField weekBasedYear() {
612c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        return weekBasedYear;
613c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    }
614c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
615c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    //-----------------------------------------------------------------------
616c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
617c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Checks if this {@code WeekFields} is equal to the specified object.
618c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * <p>
619c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * The comparison is based on the entire state of the rules, which is
620c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * the first day-of-week and minimal days.
621c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     *
622c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @param object  the other rules to compare to, null returns false
623c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @return true if this is equal to the specified rules
624c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
625c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    @Override
626c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    public boolean equals(Object object) {
627c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        if (this == object) {
628c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return true;
629c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
630c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        if (object instanceof WeekFields) {
631c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return hashCode() == object.hashCode();
632c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
633c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        return false;
634c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    }
635c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
636c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
637c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * A hash code for this {@code WeekFields}.
638c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     *
639c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @return a suitable hash code
640c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
641c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    @Override
642c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    public int hashCode() {
643c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        return firstDayOfWeek.ordinal() * 7 + minimalDays;
644c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    }
645c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
646c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    //-----------------------------------------------------------------------
647c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
648c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * A string representation of this {@code WeekFields} instance.
649c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     *
650c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * @return the string representation, not null
651c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
652c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    @Override
653c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    public String toString() {
654c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        return "WeekFields[" + firstDayOfWeek + ',' + minimalDays + ']';
655c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    }
656c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
657c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    //-----------------------------------------------------------------------
658c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    /**
659c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Field type that computes DayOfWeek, WeekOfMonth, and WeekOfYear
660c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * based on a WeekFields.
661c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * A separate Field instance is required for each different WeekFields;
662c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * combination of start of week and minimum number of days.
663c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * Constructors are provided to create fields for DayOfWeek, WeekOfMonth,
664c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     * and WeekOfYear.
665c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer     */
666c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    static class ComputedDayOfField implements TemporalField {
667c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
668c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        /**
669c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * Returns a field to access the day of week,
670c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * computed based on a WeekFields.
671c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * <p>
672c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * The WeekDefintion of the first day of the week is used with
673c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * the ISO DAY_OF_WEEK field to compute week boundaries.
674c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         */
675c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        static ComputedDayOfField ofDayOfWeekField(WeekFields weekDef) {
676c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return new ComputedDayOfField("DayOfWeek", weekDef, DAYS, WEEKS, DAY_OF_WEEK_RANGE);
677c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
678c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
679c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        /**
680c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * Returns a field to access the week of month,
681c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * computed based on a WeekFields.
682c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @see WeekFields#weekOfMonth()
683c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         */
684c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        static ComputedDayOfField ofWeekOfMonthField(WeekFields weekDef) {
685c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return new ComputedDayOfField("WeekOfMonth", weekDef, WEEKS, MONTHS, WEEK_OF_MONTH_RANGE);
686c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
687c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
688c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        /**
689c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * Returns a field to access the week of year,
690c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * computed based on a WeekFields.
691c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @see WeekFields#weekOfYear()
692c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         */
693c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        static ComputedDayOfField ofWeekOfYearField(WeekFields weekDef) {
694c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return new ComputedDayOfField("WeekOfYear", weekDef, WEEKS, YEARS, WEEK_OF_YEAR_RANGE);
695c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
696c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
697c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        /**
698c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * Returns a field to access the week of week-based-year,
699c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * computed based on a WeekFields.
700c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @see WeekFields#weekOfWeekBasedYear()
701c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         */
702c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        static ComputedDayOfField ofWeekOfWeekBasedYearField(WeekFields weekDef) {
703c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return new ComputedDayOfField("WeekOfWeekBasedYear", weekDef, WEEKS, IsoFields.WEEK_BASED_YEARS, WEEK_OF_WEEK_BASED_YEAR_RANGE);
704c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
705c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
706c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        /**
707c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * Returns a field to access the week of week-based-year,
708c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * computed based on a WeekFields.
709c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @see WeekFields#weekBasedYear()
710c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         */
711c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        static ComputedDayOfField ofWeekBasedYearField(WeekFields weekDef) {
712c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return new ComputedDayOfField("WeekBasedYear", weekDef, IsoFields.WEEK_BASED_YEARS, FOREVER, ChronoField.YEAR.range());
713c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
714c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
715c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        /**
716c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * Return a new week-based-year date of the Chronology, year, week-of-year,
717c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * and dow of week.
718c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @param chrono The chronology of the new date
719c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @param yowby the year of the week-based-year
720c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @param wowby the week of the week-based-year
721c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @param dow the day of the week
722c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @return a ChronoLocalDate for the requested year, week of year, and day of week
723c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         */
724c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        private ChronoLocalDate ofWeekBasedYear(Chronology chrono,
725c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                int yowby, int wowby, int dow) {
726c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            ChronoLocalDate date = chrono.date(yowby, 1, 1);
727c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int ldow = localizedDayOfWeek(date);
728c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int offset = startOfWeekOffset(1, ldow);
729c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
730c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            // Clamp the week of year to keep it in the same year
731c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int yearLen = date.lengthOfYear();
732c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int newYearWeek = computeWeek(offset, yearLen + weekDef.getMinimalDaysInFirstWeek());
733c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            wowby = Math.min(wowby, newYearWeek - 1);
734c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
735c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int days = -offset + (dow - 1) + (wowby - 1) * 7;
736c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return date.plus(days, DAYS);
737c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
738c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
739c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        private final String name;
740c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        private final WeekFields weekDef;
741c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        private final TemporalUnit baseUnit;
742c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        private final TemporalUnit rangeUnit;
743c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        private final ValueRange range;
744c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
745c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        private ComputedDayOfField(String name, WeekFields weekDef, TemporalUnit baseUnit, TemporalUnit rangeUnit, ValueRange range) {
746c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            this.name = name;
747c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            this.weekDef = weekDef;
748c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            this.baseUnit = baseUnit;
749c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            this.rangeUnit = rangeUnit;
750c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            this.range = range;
751c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
752c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
753c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        private static final ValueRange DAY_OF_WEEK_RANGE = ValueRange.of(1, 7);
754c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        private static final ValueRange WEEK_OF_MONTH_RANGE = ValueRange.of(0, 1, 4, 6);
755c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        private static final ValueRange WEEK_OF_YEAR_RANGE = ValueRange.of(0, 1, 52, 54);
756c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        private static final ValueRange WEEK_OF_WEEK_BASED_YEAR_RANGE = ValueRange.of(1, 52, 53);
757c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
758c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        @Override
759c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        public long getFrom(TemporalAccessor temporal) {
760c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            if (rangeUnit == WEEKS) {  // day-of-week
761c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                return localizedDayOfWeek(temporal);
762c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            } else if (rangeUnit == MONTHS) {  // week-of-month
763c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                return localizedWeekOfMonth(temporal);
764c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            } else if (rangeUnit == YEARS) {  // week-of-year
765c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                return localizedWeekOfYear(temporal);
766c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            } else if (rangeUnit == WEEK_BASED_YEARS) {
767c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                return localizedWeekOfWeekBasedYear(temporal);
768c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            } else if (rangeUnit == FOREVER) {
769c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                return localizedWeekBasedYear(temporal);
770c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            } else {
771c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                throw new IllegalStateException("unreachable, rangeUnit: " + rangeUnit + ", this: " + this);
772c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            }
773c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
774c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
775c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        private int localizedDayOfWeek(TemporalAccessor temporal) {
776c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int sow = weekDef.getFirstDayOfWeek().getValue();
777c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int isoDow = temporal.get(DAY_OF_WEEK);
778c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return Math.floorMod(isoDow - sow, 7) + 1;
779c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
780c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
781c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        private int localizedDayOfWeek(int isoDow) {
782c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int sow = weekDef.getFirstDayOfWeek().getValue();
783c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return Math.floorMod(isoDow - sow, 7) + 1;
784c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
785c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
786c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        private long localizedWeekOfMonth(TemporalAccessor temporal) {
787c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int dow = localizedDayOfWeek(temporal);
788c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int dom = temporal.get(DAY_OF_MONTH);
789c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int offset = startOfWeekOffset(dom, dow);
790c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return computeWeek(offset, dom);
791c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
792c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
793c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        private long localizedWeekOfYear(TemporalAccessor temporal) {
794c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int dow = localizedDayOfWeek(temporal);
795c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int doy = temporal.get(DAY_OF_YEAR);
796c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int offset = startOfWeekOffset(doy, dow);
797c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return computeWeek(offset, doy);
798c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
799c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
800c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        /**
801c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * Returns the year of week-based-year for the temporal.
802c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * The year can be the previous year, the current year, or the next year.
803c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @param temporal a date of any chronology, not null
804c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @return the year of week-based-year for the date
805c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         */
806c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        private int localizedWeekBasedYear(TemporalAccessor temporal) {
807c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int dow = localizedDayOfWeek(temporal);
808c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int year = temporal.get(YEAR);
809c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int doy = temporal.get(DAY_OF_YEAR);
810c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int offset = startOfWeekOffset(doy, dow);
811c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int week = computeWeek(offset, doy);
812c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            if (week == 0) {
813c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                // Day is in end of week of previous year; return the previous year
814c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                return year - 1;
815c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            } else {
816c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                // If getting close to end of year, use higher precision logic
817c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                // Check if date of year is in partial week associated with next year
818c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                ValueRange dayRange = temporal.range(DAY_OF_YEAR);
819c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                int yearLen = (int)dayRange.getMaximum();
820c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                int newYearWeek = computeWeek(offset, yearLen + weekDef.getMinimalDaysInFirstWeek());
821c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                if (week >= newYearWeek) {
822c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                    return year + 1;
823c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                }
824c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            }
825c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return year;
826c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
827c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
828c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        /**
829c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * Returns the week of week-based-year for the temporal.
830c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * The week can be part of the previous year, the current year,
831c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * or the next year depending on the week start and minimum number
832c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * of days.
833c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @param temporal  a date of any chronology
834c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @return the week of the year
835c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @see #localizedWeekBasedYear(java.time.temporal.TemporalAccessor)
836c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         */
837c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        private int localizedWeekOfWeekBasedYear(TemporalAccessor temporal) {
838c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int dow = localizedDayOfWeek(temporal);
839c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int doy = temporal.get(DAY_OF_YEAR);
840c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int offset = startOfWeekOffset(doy, dow);
841c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int week = computeWeek(offset, doy);
842c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            if (week == 0) {
843c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                // Day is in end of week of previous year
844c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                // Recompute from the last day of the previous year
845c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                ChronoLocalDate date = Chronology.from(temporal).date(temporal);
846c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                date = date.minus(doy, DAYS);   // Back down into previous year
847c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                return localizedWeekOfWeekBasedYear(date);
848c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            } else if (week > 50) {
849c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                // If getting close to end of year, use higher precision logic
850c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                // Check if date of year is in partial week associated with next year
851c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                ValueRange dayRange = temporal.range(DAY_OF_YEAR);
852c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                int yearLen = (int)dayRange.getMaximum();
853c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                int newYearWeek = computeWeek(offset, yearLen + weekDef.getMinimalDaysInFirstWeek());
854c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                if (week >= newYearWeek) {
855c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                    // Overlaps with week of following year; reduce to week in following year
856c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                    week = week - newYearWeek + 1;
857c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                }
858c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            }
859c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return week;
860c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
861c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
862c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        /**
863c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * Returns an offset to align week start with a day of month or day of year.
864c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         *
865c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @param day  the day; 1 through infinity
866c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @param dow  the day of the week of that day; 1 through 7
867c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @return  an offset in days to align a day with the start of the first 'full' week
868c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         */
869c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        private int startOfWeekOffset(int day, int dow) {
870c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            // offset of first day corresponding to the day of week in first 7 days (zero origin)
871c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int weekStart = Math.floorMod(day - dow, 7);
872c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int offset = -weekStart;
873c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            if (weekStart + 1 > weekDef.getMinimalDaysInFirstWeek()) {
874c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                // The previous week has the minimum days in the current month to be a 'week'
875c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                offset = 7 - weekStart;
876c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            }
877c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return offset;
878c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
879c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
880c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        /**
881c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * Returns the week number computed from the reference day and reference dayOfWeek.
882c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         *
883c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @param offset the offset to align a date with the start of week
884c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         *     from {@link #startOfWeekOffset}.
885c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @param day  the day for which to compute the week number
886c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @return the week number where zero is used for a partial week and 1 for the first full week
887c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         */
888c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        private int computeWeek(int offset, int day) {
889c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return ((7 + offset + (day - 1)) / 7);
890c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
891c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
892c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        @SuppressWarnings("unchecked")
893c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        @Override
894c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        public <R extends Temporal> R adjustInto(R temporal, long newValue) {
895c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            // Check the new value and get the old value of the field
896c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int newVal = range.checkValidIntValue(newValue, this);  // lenient check range
897c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int currentVal = temporal.get(this);
898c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            if (newVal == currentVal) {
899c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                return temporal;
900c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            }
901c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
902c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            if (rangeUnit == FOREVER) {     // replace year of WeekBasedYear
903c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                // Create a new date object with the same chronology,
904c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                // the desired year and the same week and dow.
905c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                int idow = temporal.get(weekDef.dayOfWeek);
906c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                int wowby = temporal.get(weekDef.weekOfWeekBasedYear);
907c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                return (R) ofWeekBasedYear(Chronology.from(temporal), (int)newValue, wowby, idow);
908c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            } else {
909c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                // Compute the difference and add that using the base unit of the field
910c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                return (R) temporal.plus(newVal - currentVal, baseUnit);
911c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            }
912c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
913c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
914c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        @Override
915c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        public ChronoLocalDate resolve(
916c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                Map<TemporalField, Long> fieldValues, TemporalAccessor partialTemporal, ResolverStyle resolverStyle) {
917c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            final long value = fieldValues.get(this);
918c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            final int newValue = Math.toIntExact(value);  // broad limit makes overflow checking lighter
919c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            // first convert localized day-of-week to ISO day-of-week
920c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            // doing this first handles case where both ISO and localized were parsed and might mismatch
921c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            // day-of-week is always strict as two different day-of-week values makes lenient complex
922c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            if (rangeUnit == WEEKS) {  // day-of-week
923c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                final int checkedValue = range.checkValidIntValue(value, this);  // no leniency as too complex
924c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                final int startDow = weekDef.getFirstDayOfWeek().getValue();
925c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                long isoDow = Math.floorMod((startDow - 1) + (checkedValue - 1), 7) + 1;
926c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                fieldValues.remove(this);
927c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                fieldValues.put(DAY_OF_WEEK, isoDow);
928c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                return null;
929c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            }
930c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
931c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            // can only build date if ISO day-of-week is present
932c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            if (fieldValues.containsKey(DAY_OF_WEEK) == false) {
933c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                return null;
934c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            }
935c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int isoDow = DAY_OF_WEEK.checkValidIntValue(fieldValues.get(DAY_OF_WEEK));
936c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int dow = localizedDayOfWeek(isoDow);
937c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
938c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            // build date
939c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            Chronology chrono = Chronology.from(partialTemporal);
940c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            if (fieldValues.containsKey(YEAR)) {
941c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                int year = YEAR.checkValidIntValue(fieldValues.get(YEAR));  // validate
942c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                if (rangeUnit == MONTHS && fieldValues.containsKey(MONTH_OF_YEAR)) {  // week-of-month
943c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                    long month = fieldValues.get(MONTH_OF_YEAR);  // not validated yet
944c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                    return resolveWoM(fieldValues, chrono, year, month, newValue, dow, resolverStyle);
945c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                }
946c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                if (rangeUnit == YEARS) {  // week-of-year
947c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                    return resolveWoY(fieldValues, chrono, year, newValue, dow, resolverStyle);
948c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                }
949c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            } else if ((rangeUnit == WEEK_BASED_YEARS || rangeUnit == FOREVER) &&
950c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                    fieldValues.containsKey(weekDef.weekBasedYear) &&
951c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                    fieldValues.containsKey(weekDef.weekOfWeekBasedYear)) { // week-of-week-based-year and year-of-week-based-year
952c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                return resolveWBY(fieldValues, chrono, dow, resolverStyle);
953c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            }
954c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return null;
955c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
956c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
957c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        private ChronoLocalDate resolveWoM(
958c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                Map<TemporalField, Long> fieldValues, Chronology chrono, int year, long month, long wom, int localDow, ResolverStyle resolverStyle) {
959c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            ChronoLocalDate date;
960c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            if (resolverStyle == ResolverStyle.LENIENT) {
961c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                date = chrono.date(year, 1, 1).plus(Math.subtractExact(month, 1), MONTHS);
962c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                long weeks = Math.subtractExact(wom, localizedWeekOfMonth(date));
963c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                int days = localDow - localizedDayOfWeek(date);  // safe from overflow
964c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                date = date.plus(Math.addExact(Math.multiplyExact(weeks, 7), days), DAYS);
965c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            } else {
966c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                int monthValid = MONTH_OF_YEAR.checkValidIntValue(month);  // validate
967c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                date = chrono.date(year, monthValid, 1);
968c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                int womInt = range.checkValidIntValue(wom, this);  // validate
969c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                int weeks = (int) (womInt - localizedWeekOfMonth(date));  // safe from overflow
970c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                int days = localDow - localizedDayOfWeek(date);  // safe from overflow
971c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                date = date.plus(weeks * 7 + days, DAYS);
972c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                if (resolverStyle == ResolverStyle.STRICT && date.getLong(MONTH_OF_YEAR) != month) {
973c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                    throw new DateTimeException("Strict mode rejected resolved date as it is in a different month");
974c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                }
975c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            }
976c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            fieldValues.remove(this);
977c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            fieldValues.remove(YEAR);
978c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            fieldValues.remove(MONTH_OF_YEAR);
979c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            fieldValues.remove(DAY_OF_WEEK);
980c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return date;
981c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
982c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
983c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        private ChronoLocalDate resolveWoY(
984c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                Map<TemporalField, Long> fieldValues, Chronology chrono, int year, long woy, int localDow, ResolverStyle resolverStyle) {
985c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            ChronoLocalDate date = chrono.date(year, 1, 1);
986c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            if (resolverStyle == ResolverStyle.LENIENT) {
987c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                long weeks = Math.subtractExact(woy, localizedWeekOfYear(date));
988c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                int days = localDow - localizedDayOfWeek(date);  // safe from overflow
989c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                date = date.plus(Math.addExact(Math.multiplyExact(weeks, 7), days), DAYS);
990c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            } else {
991c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                int womInt = range.checkValidIntValue(woy, this);  // validate
992c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                int weeks = (int) (womInt - localizedWeekOfYear(date));  // safe from overflow
993c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                int days = localDow - localizedDayOfWeek(date);  // safe from overflow
994c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                date = date.plus(weeks * 7 + days, DAYS);
995c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                if (resolverStyle == ResolverStyle.STRICT && date.getLong(YEAR) != year) {
996c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                    throw new DateTimeException("Strict mode rejected resolved date as it is in a different year");
997c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                }
998c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            }
999c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            fieldValues.remove(this);
1000c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            fieldValues.remove(YEAR);
1001c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            fieldValues.remove(DAY_OF_WEEK);
1002c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return date;
1003c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
1004c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
1005c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        private ChronoLocalDate resolveWBY(
1006c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                Map<TemporalField, Long> fieldValues, Chronology chrono, int localDow, ResolverStyle resolverStyle) {
1007c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int yowby = weekDef.weekBasedYear.range().checkValidIntValue(
1008c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                    fieldValues.get(weekDef.weekBasedYear), weekDef.weekBasedYear);
1009c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            ChronoLocalDate date;
1010c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            if (resolverStyle == ResolverStyle.LENIENT) {
1011c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                date = ofWeekBasedYear(chrono, yowby, 1, localDow);
1012c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                long wowby = fieldValues.get(weekDef.weekOfWeekBasedYear);
1013c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                long weeks = Math.subtractExact(wowby, 1);
1014c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                date = date.plus(weeks, WEEKS);
1015c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            } else {
1016c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                int wowby = weekDef.weekOfWeekBasedYear.range().checkValidIntValue(
1017c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                        fieldValues.get(weekDef.weekOfWeekBasedYear), weekDef.weekOfWeekBasedYear);  // validate
1018c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                date = ofWeekBasedYear(chrono, yowby, wowby, localDow);
1019c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                if (resolverStyle == ResolverStyle.STRICT && localizedWeekBasedYear(date) != yowby) {
1020c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                    throw new DateTimeException("Strict mode rejected resolved date as it is in a different week-based-year");
1021c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                }
1022c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            }
1023c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            fieldValues.remove(this);
1024c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            fieldValues.remove(weekDef.weekBasedYear);
1025c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            fieldValues.remove(weekDef.weekOfWeekBasedYear);
1026c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            fieldValues.remove(DAY_OF_WEEK);
1027c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return date;
1028c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
1029c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
1030c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        //-----------------------------------------------------------------------
1031c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        @Override
1032c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        public String getDisplayName(Locale locale) {
1033c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            Objects.requireNonNull(locale, "locale");
1034c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            if (rangeUnit == YEARS) {  // only have values for week-of-year
10356975f84c2ed72e1e26d20190b6f318718c849008Tobias Thierer                // Android-changed: Use ICU name values.
1036d7928577b0cc656c1c6da16bfe281541fdd435eeJoachim Sauer                DateTimePatternGenerator dateTimePatternGenerator = DateTimePatternGenerator
1037d7928577b0cc656c1c6da16bfe281541fdd435eeJoachim Sauer                        .getFrozenInstance(ULocale.forLocale(locale));
1038d7928577b0cc656c1c6da16bfe281541fdd435eeJoachim Sauer                String icuName = dateTimePatternGenerator
1039d7928577b0cc656c1c6da16bfe281541fdd435eeJoachim Sauer                        .getAppendItemName(DateTimePatternGenerator.WEEK_OF_YEAR);
1040d7928577b0cc656c1c6da16bfe281541fdd435eeJoachim Sauer                return icuName != null && !icuName.isEmpty() ? icuName : name;
1041c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            }
1042c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return name;
1043c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
1044c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
1045c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        @Override
1046c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        public TemporalUnit getBaseUnit() {
1047c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return baseUnit;
1048c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
1049c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
1050c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        @Override
1051c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        public TemporalUnit getRangeUnit() {
1052c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return rangeUnit;
1053c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
1054c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
1055c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        @Override
1056c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        public boolean isDateBased() {
1057c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return true;
1058c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
1059c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
1060c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        @Override
1061c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        public boolean isTimeBased() {
1062c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return false;
1063c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
1064c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
1065c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        @Override
1066c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        public ValueRange range() {
1067c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return range;
1068c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
1069c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
1070c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        //-----------------------------------------------------------------------
1071c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        @Override
1072c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        public boolean isSupportedBy(TemporalAccessor temporal) {
1073c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            if (temporal.isSupported(DAY_OF_WEEK)) {
1074c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                if (rangeUnit == WEEKS) {  // day-of-week
1075c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                    return true;
1076c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                } else if (rangeUnit == MONTHS) {  // week-of-month
1077c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                    return temporal.isSupported(DAY_OF_MONTH);
1078c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                } else if (rangeUnit == YEARS) {  // week-of-year
1079c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                    return temporal.isSupported(DAY_OF_YEAR);
1080c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                } else if (rangeUnit == WEEK_BASED_YEARS) {
1081c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                    return temporal.isSupported(DAY_OF_YEAR);
1082c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                } else if (rangeUnit == FOREVER) {
1083c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                    return temporal.isSupported(YEAR);
1084c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                }
1085c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            }
1086c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return false;
1087c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
1088c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
1089c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        @Override
1090c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        public ValueRange rangeRefinedBy(TemporalAccessor temporal) {
1091c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            if (rangeUnit == ChronoUnit.WEEKS) {  // day-of-week
1092c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                return range;
1093c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            } else if (rangeUnit == MONTHS) {  // week-of-month
1094c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                return rangeByWeek(temporal, DAY_OF_MONTH);
1095c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            } else if (rangeUnit == YEARS) {  // week-of-year
1096c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                return rangeByWeek(temporal, DAY_OF_YEAR);
1097c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            } else if (rangeUnit == WEEK_BASED_YEARS) {
1098c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                return rangeWeekOfWeekBasedYear(temporal);
1099c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            } else if (rangeUnit == FOREVER) {
1100c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                return YEAR.range();
1101c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            } else {
1102c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                throw new IllegalStateException("unreachable, rangeUnit: " + rangeUnit + ", this: " + this);
1103c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            }
1104c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
1105c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
1106c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        /**
1107c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * Map the field range to a week range
1108c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @param temporal the temporal
1109c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @param field the field to get the range of
1110c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @return the ValueRange with the range adjusted to weeks.
1111c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         */
1112c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        private ValueRange rangeByWeek(TemporalAccessor temporal, TemporalField field) {
1113c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int dow = localizedDayOfWeek(temporal);
1114c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int offset = startOfWeekOffset(temporal.get(field), dow);
1115c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            ValueRange fieldRange = temporal.range(field);
1116c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return ValueRange.of(computeWeek(offset, (int) fieldRange.getMinimum()),
1117c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                    computeWeek(offset, (int) fieldRange.getMaximum()));
1118c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
1119c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
1120c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        /**
1121c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * Map the field range to a week range of a week year.
1122c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @param temporal  the temporal
1123c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         * @return the ValueRange with the range adjusted to weeks.
1124c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer         */
1125c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        private ValueRange rangeWeekOfWeekBasedYear(TemporalAccessor temporal) {
1126c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            if (!temporal.isSupported(DAY_OF_YEAR)) {
1127c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                return WEEK_OF_YEAR_RANGE;
1128c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            }
1129c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int dow = localizedDayOfWeek(temporal);
1130c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int doy = temporal.get(DAY_OF_YEAR);
1131c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int offset = startOfWeekOffset(doy, dow);
1132c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int week = computeWeek(offset, doy);
1133c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            if (week == 0) {
1134c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                // Day is in end of week of previous year
1135c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                // Recompute from the last day of the previous year
1136c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                ChronoLocalDate date = Chronology.from(temporal).date(temporal);
1137c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                date = date.minus(doy + 7, DAYS);   // Back down into previous year
1138c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                return rangeWeekOfWeekBasedYear(date);
1139c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            }
1140c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            // Check if day of year is in partial week associated with next year
1141c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            ValueRange dayRange = temporal.range(DAY_OF_YEAR);
1142c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int yearLen = (int)dayRange.getMaximum();
1143c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            int newYearWeek = computeWeek(offset, yearLen + weekDef.getMinimalDaysInFirstWeek());
1144c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
1145c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            if (week >= newYearWeek) {
1146c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                // Overlaps with weeks of following year; recompute from a week in following year
1147c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                ChronoLocalDate date = Chronology.from(temporal).date(temporal);
1148c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                date = date.plus(yearLen - doy + 1 + 7, ChronoUnit.DAYS);
1149c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer                return rangeWeekOfWeekBasedYear(date);
1150c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            }
1151c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return ValueRange.of(1, newYearWeek-1);
1152c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
1153c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer
1154c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        //-----------------------------------------------------------------------
1155c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        @Override
1156c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        public String toString() {
1157c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer            return name + "[" + weekDef.toString() + "]";
1158c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer        }
1159c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer    }
1160c9dd3385ea6f927052783f42fb1282fb093e636eJoachim Sauer}
1161