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