src/share/classes/java/time/temporal/WeekFields.java

Print this page

        

*** 59,77 **** * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package java.time.temporal; import java.io.InvalidObjectException; import java.io.Serializable; import java.time.DayOfWeek; ! import java.time.format.DateTimeBuilder; ! import java.util.GregorianCalendar; import java.util.Locale; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; /** * Localized definitions of the day-of-week, week-of-month and week-of-year fields. * <p> * A standard week is seven days long, but cultures have different definitions for some --- 59,92 ---- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package java.time.temporal; + import static java.time.temporal.ChronoField.DAY_OF_MONTH; + import static java.time.temporal.ChronoField.DAY_OF_WEEK; + import static java.time.temporal.ChronoField.DAY_OF_YEAR; + import static java.time.temporal.ChronoField.EPOCH_DAY; + import static java.time.temporal.ChronoField.MONTH_OF_YEAR; + import static java.time.temporal.ChronoField.YEAR; + import static java.time.temporal.ChronoUnit.DAYS; + import static java.time.temporal.ChronoUnit.MONTHS; + import static java.time.temporal.ChronoUnit.WEEKS; + import static java.time.temporal.ChronoUnit.YEARS; + import java.io.InvalidObjectException; import java.io.Serializable; import java.time.DayOfWeek; ! import java.time.chrono.ChronoLocalDate; ! import java.time.chrono.Chronology; ! import java.util.Collections; ! import java.util.HashMap; import java.util.Locale; + import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; + import sun.util.locale.provider.CalendarDataUtility; /** * Localized definitions of the day-of-week, week-of-month and week-of-year fields. * <p> * A standard week is seven days long, but cultures have different definitions for some
*** 133,144 **** */ public final class WeekFields implements Serializable { // implementation notes // querying week-of-month or week-of-year should return the week value bound within the month/year // however, setting the week value should be lenient (use plus/minus weeks) ! // allow week-of-month outer range [0 to 5] ! // allow week-of-year outer range [0 to 53] // this is because callers shouldn't be expected to know the details of validity /** * The cache of rules by firstDayOfWeek plus minimalDays. * Initialized first to be available for definition of ISO, etc. --- 148,159 ---- */ public final class WeekFields implements Serializable { // implementation notes // querying week-of-month or week-of-year should return the week value bound within the month/year // however, setting the week value should be lenient (use plus/minus weeks) ! // allow week-of-month outer range [0 to 6] ! // allow week-of-year outer range [0 to 54] // this is because callers shouldn't be expected to know the details of validity /** * The cache of rules by firstDayOfWeek plus minimalDays. * Initialized first to be available for definition of ISO, etc.
*** 207,222 **** */ public static WeekFields of(Locale locale) { Objects.requireNonNull(locale, "locale"); locale = new Locale(locale.getLanguage(), locale.getCountry()); // elminate variants ! // obtain these from GregorianCalendar for now ! // TODO: consider getting them directly from the spi ! GregorianCalendar gcal = new GregorianCalendar(locale); ! int calDow = gcal.getFirstDayOfWeek(); DayOfWeek dow = DayOfWeek.SUNDAY.plus(calDow - 1); ! int minDays = gcal.getMinimalDaysInFirstWeek(); return WeekFields.of(dow, minDays); } /** * Obtains an instance of {@code WeekFields} from the first day-of-week and minimal days. --- 222,234 ---- */ public static WeekFields of(Locale locale) { Objects.requireNonNull(locale, "locale"); locale = new Locale(locale.getLanguage(), locale.getCountry()); // elminate variants ! int calDow = CalendarDataUtility.retrieveFirstDayOfWeek(locale); DayOfWeek dow = DayOfWeek.SUNDAY.plus(calDow - 1); ! int minDays = CalendarDataUtility.retrieveMinimalDaysInFirstWeek(locale); return WeekFields.of(dow, minDays); } /** * Obtains an instance of {@code WeekFields} from the first day-of-week and minimal days.
*** 435,466 **** * <p> * The WeekDefintion of the first day of the week is used with * the ISO DAY_OF_WEEK field to compute week boundaries. */ static ComputedDayOfField ofDayOfWeekField(WeekFields weekDef) { ! return new ComputedDayOfField("DayOfWeek", weekDef, ! ChronoUnit.DAYS, ChronoUnit.WEEKS, DAY_OF_WEEK_RANGE); } /** * Returns a field to access the week of month, * computed based on a WeekFields. * @see WeekFields#weekOfMonth() */ static ComputedDayOfField ofWeekOfMonthField(WeekFields weekDef) { ! return new ComputedDayOfField("WeekOfMonth", weekDef, ! ChronoUnit.WEEKS, ChronoUnit.MONTHS, WEEK_OF_MONTH_RANGE); } /** * Returns a field to access the week of year, * computed based on a WeekFields. * @see WeekFields#weekOfYear() */ static ComputedDayOfField ofWeekOfYearField(WeekFields weekDef) { ! return new ComputedDayOfField("WeekOfYear", weekDef, ! ChronoUnit.WEEKS, ChronoUnit.YEARS, WEEK_OF_YEAR_RANGE); } private final String name; private final WeekFields weekDef; private final TemporalUnit baseUnit; private final TemporalUnit rangeUnit; --- 447,475 ---- * <p> * The WeekDefintion of the first day of the week is used with * the ISO DAY_OF_WEEK field to compute week boundaries. */ static ComputedDayOfField ofDayOfWeekField(WeekFields weekDef) { ! return new ComputedDayOfField("DayOfWeek", weekDef, DAYS, WEEKS, DAY_OF_WEEK_RANGE); } /** * Returns a field to access the week of month, * computed based on a WeekFields. * @see WeekFields#weekOfMonth() */ static ComputedDayOfField ofWeekOfMonthField(WeekFields weekDef) { ! return new ComputedDayOfField("WeekOfMonth", weekDef, WEEKS, MONTHS, WEEK_OF_MONTH_RANGE); } /** * Returns a field to access the week of year, * computed based on a WeekFields. * @see WeekFields#weekOfYear() */ static ComputedDayOfField ofWeekOfYearField(WeekFields weekDef) { ! return new ComputedDayOfField("WeekOfYear", weekDef, WEEKS, YEARS, WEEK_OF_YEAR_RANGE); } private final String name; private final WeekFields weekDef; private final TemporalUnit baseUnit; private final TemporalUnit rangeUnit;
*** 473,505 **** this.rangeUnit = rangeUnit; this.range = range; } private static final ValueRange DAY_OF_WEEK_RANGE = ValueRange.of(1, 7); ! private static final ValueRange WEEK_OF_MONTH_RANGE = ValueRange.of(0, 1, 4, 5); ! private static final ValueRange WEEK_OF_YEAR_RANGE = ValueRange.of(0, 1, 52, 53); @Override ! public long doGet(TemporalAccessor temporal) { // Offset the ISO DOW by the start of this week int sow = weekDef.getFirstDayOfWeek().getValue(); ! int isoDow = temporal.get(ChronoField.DAY_OF_WEEK); ! int dow = Math.floorMod(isoDow - sow, 7) + 1; ! if (rangeUnit == ChronoUnit.WEEKS) { return dow; ! } else if (rangeUnit == ChronoUnit.MONTHS) { ! int dom = temporal.get(ChronoField.DAY_OF_MONTH); int offset = startOfWeekOffset(dom, dow); return computeWeek(offset, dom); ! } else if (rangeUnit == ChronoUnit.YEARS) { ! int doy = temporal.get(ChronoField.DAY_OF_YEAR); int offset = startOfWeekOffset(doy, dow); return computeWeek(offset, doy); - } else { - throw new IllegalStateException("unreachable"); - } } /** * Returns an offset to align week start with a day of month or day of year. * --- 482,526 ---- this.rangeUnit = rangeUnit; this.range = range; } private static final ValueRange DAY_OF_WEEK_RANGE = ValueRange.of(1, 7); ! private static final ValueRange WEEK_OF_MONTH_RANGE = ValueRange.of(0, 1, 4, 6); ! private static final ValueRange WEEK_OF_YEAR_RANGE = ValueRange.of(0, 1, 52, 54); @Override ! public long getFrom(TemporalAccessor temporal) { // Offset the ISO DOW by the start of this week int sow = weekDef.getFirstDayOfWeek().getValue(); ! int dow = localizedDayOfWeek(temporal, sow); ! if (rangeUnit == WEEKS) { // day-of-week return dow; ! } else if (rangeUnit == MONTHS) { // week-of-month ! return localizedWeekOfMonth(temporal, dow); ! } else if (rangeUnit == YEARS) { // week-of-year ! return localizedWeekOfYear(temporal, dow); ! } else { ! throw new IllegalStateException("unreachable"); ! } ! } ! ! private int localizedDayOfWeek(TemporalAccessor temporal, int sow) { ! int isoDow = temporal.get(DAY_OF_WEEK); ! return Math.floorMod(isoDow - sow, 7) + 1; ! } ! ! private long localizedWeekOfMonth(TemporalAccessor temporal, int dow) { ! int dom = temporal.get(DAY_OF_MONTH); int offset = startOfWeekOffset(dom, dow); return computeWeek(offset, dom); ! } ! ! private long localizedWeekOfYear(TemporalAccessor temporal, int dow) { ! int doy = temporal.get(DAY_OF_YEAR); int offset = startOfWeekOffset(doy, dow); return computeWeek(offset, doy); } /** * Returns an offset to align week start with a day of month or day of year. *
*** 528,590 **** */ private int computeWeek(int offset, int day) { return ((7 + offset + (day - 1)) / 7); } @Override ! public <R extends Temporal> R doWith(R temporal, long newValue) { // Check the new value and get the old value of the field ! int newVal = range.checkValidIntValue(newValue, this); int currentVal = temporal.get(this); if (newVal == currentVal) { return temporal; } // Compute the difference and add that using the base using of the field ! int delta = newVal - currentVal; ! return (R) temporal.plus(delta, baseUnit); } @Override ! public boolean resolve(DateTimeBuilder builder, long value) { int newValue = range.checkValidIntValue(value, this); - // DOW and YEAR are necessary for all fields; Chrono defaults to ISO if not present int sow = weekDef.getFirstDayOfWeek().getValue(); ! int dow = builder.get(weekDef.dayOfWeek()); ! int year = builder.get(ChronoField.YEAR); ! Chrono chrono = Chrono.from(builder); ! ! // The WOM and WOY fields are the critical values ! if (rangeUnit == ChronoUnit.MONTHS) { ! // Process WOM value by combining with DOW and MONTH, YEAR ! int month = builder.get(ChronoField.MONTH_OF_YEAR); ! ChronoLocalDate cd = chrono.date(year, month, 1); ! int offset = startOfWeekOffset(1, cd.get(weekDef.dayOfWeek())); ! offset += dow - 1; // offset to desired day of week ! offset += 7 * (newValue - 1); // offset by week number ! ChronoLocalDate result = cd.plus(offset, ChronoUnit.DAYS); ! builder.addFieldValue(ChronoField.DAY_OF_MONTH, result.get(ChronoField.DAY_OF_MONTH)); ! builder.removeFieldValue(this); ! builder.removeFieldValue(weekDef.dayOfWeek()); ! return true; ! } else if (rangeUnit == ChronoUnit.YEARS) { ! // Process WOY ! ChronoLocalDate cd = chrono.date(year, 1, 1); ! int offset = startOfWeekOffset(1, cd.get(weekDef.dayOfWeek())); ! offset += dow - 1; // offset to desired day of week ! offset += 7 * (newValue - 1); // offset by week number ! ChronoLocalDate result = cd.plus(offset, ChronoUnit.DAYS); ! builder.addFieldValue(ChronoField.DAY_OF_MONTH, result.get(ChronoField.DAY_OF_MONTH)); ! builder.addFieldValue(ChronoField.MONTH_OF_YEAR, result.get(ChronoField.MONTH_OF_YEAR)); ! builder.removeFieldValue(this); ! builder.removeFieldValue(weekDef.dayOfWeek()); ! return true; } else { ! // ignore DOW of WEEK field; the value will be processed by WOM or WOY ! int isoDow = Math.floorMod((sow - 1) + (dow - 1), 7) + 1; ! builder.addFieldValue(ChronoField.DAY_OF_WEEK, isoDow); ! // Not removed, the week-of-xxx fields need this value ! return true; } } //----------------------------------------------------------------------- @Override --- 549,614 ---- */ private int computeWeek(int offset, int day) { return ((7 + offset + (day - 1)) / 7); } + @SuppressWarnings("unchecked") @Override ! public <R extends Temporal> R adjustInto(R temporal, long newValue) { // Check the new value and get the old value of the field ! int newVal = range.checkValidIntValue(newValue, this); // lenient check range int currentVal = temporal.get(this); if (newVal == currentVal) { return temporal; } // Compute the difference and add that using the base using of the field ! return (R) temporal.plus(newVal - currentVal, baseUnit); } @Override ! public Map<TemporalField, Long> resolve(TemporalAccessor temporal, long value) { int newValue = range.checkValidIntValue(value, this); int sow = weekDef.getFirstDayOfWeek().getValue(); ! if (rangeUnit == WEEKS) { // day-of-week ! int isoDow = Math.floorMod((sow - 1) + (newValue - 1), 7) + 1; ! return Collections.<TemporalField, Long>singletonMap(DAY_OF_WEEK, (long) isoDow); ! } ! if ((temporal.isSupported(YEAR) && temporal.isSupported(DAY_OF_WEEK)) == false) { ! return null; ! } ! int dow = localizedDayOfWeek(temporal, sow); ! int year = temporal.get(YEAR); ! Chronology chrono = Chronology.from(temporal); // defaults to ISO ! if (rangeUnit == MONTHS) { // week-of-month ! if (temporal.isSupported(MONTH_OF_YEAR) == false) { ! return null; ! } ! int month = temporal.get(ChronoField.MONTH_OF_YEAR); ! ChronoLocalDate date = chrono.date(year, month, 1); ! int dateDow = localizedDayOfWeek(date, sow); ! long weeks = newValue - localizedWeekOfMonth(date, dateDow); ! int days = dow - dateDow; ! date = date.plus(weeks * 7 + days, DAYS); ! Map<TemporalField, Long> result = new HashMap<>(4, 1.0f); ! result.put(EPOCH_DAY, date.toEpochDay()); ! result.put(YEAR, null); ! result.put(MONTH_OF_YEAR, null); ! result.put(DAY_OF_WEEK, null); ! return result; ! } else if (rangeUnit == YEARS) { // week-of-year ! ChronoLocalDate date = chrono.date(year, 1, 1); ! int dateDow = localizedDayOfWeek(date, sow); ! long weeks = newValue - localizedWeekOfYear(date, dateDow); ! int days = dow - dateDow; ! date = date.plus(weeks * 7 + days, DAYS); ! Map<TemporalField, Long> result = new HashMap<>(4, 1.0f); ! result.put(EPOCH_DAY, date.toEpochDay()); ! result.put(YEAR, null); ! result.put(DAY_OF_WEEK, null); ! return result; } else { ! throw new IllegalStateException("unreachable"); } } //----------------------------------------------------------------------- @Override
*** 605,654 **** @Override public ValueRange range() { return range; } - //------------------------------------------------------------------------- - @Override - public int compare(TemporalAccessor temporal1, TemporalAccessor temporal2) { - return Long.compare(temporal1.getLong(this), temporal2.getLong(this)); - } - //----------------------------------------------------------------------- @Override ! public boolean doIsSupported(TemporalAccessor temporal) { ! if (temporal.isSupported(ChronoField.DAY_OF_WEEK)) { ! if (rangeUnit == ChronoUnit.WEEKS) { return true; ! } else if (rangeUnit == ChronoUnit.MONTHS) { ! return temporal.isSupported(ChronoField.DAY_OF_MONTH); ! } else if (rangeUnit == ChronoUnit.YEARS) { ! return temporal.isSupported(ChronoField.DAY_OF_YEAR); } } return false; } @Override ! public ValueRange doRange(TemporalAccessor temporal) { ! if (rangeUnit == ChronoUnit.WEEKS) { return range; } TemporalField field = null; ! if (rangeUnit == ChronoUnit.MONTHS) { ! field = ChronoField.DAY_OF_MONTH; ! } else if (rangeUnit == ChronoUnit.YEARS) { ! field = ChronoField.DAY_OF_YEAR; } else { throw new IllegalStateException("unreachable"); } // Offset the ISO DOW by the start of this week int sow = weekDef.getFirstDayOfWeek().getValue(); ! int isoDow = temporal.get(ChronoField.DAY_OF_WEEK); ! int dow = Math.floorMod(isoDow - sow, 7) + 1; int offset = startOfWeekOffset(temporal.get(field), dow); ValueRange fieldRange = temporal.range(field); return ValueRange.of(computeWeek(offset, (int) fieldRange.getMinimum()), computeWeek(offset, (int) fieldRange.getMaximum())); --- 629,671 ---- @Override public ValueRange range() { return range; } //----------------------------------------------------------------------- @Override ! public boolean isSupportedBy(TemporalAccessor temporal) { ! if (temporal.isSupported(DAY_OF_WEEK)) { ! if (rangeUnit == WEEKS) { // day-of-week return true; ! } else if (rangeUnit == MONTHS) { // week-of-month ! return temporal.isSupported(DAY_OF_MONTH); ! } else if (rangeUnit == YEARS) { // week-of-year ! return temporal.isSupported(DAY_OF_YEAR); } } return false; } @Override ! public ValueRange rangeRefinedBy(TemporalAccessor temporal) { ! if (rangeUnit == ChronoUnit.WEEKS) { // day-of-week return range; } TemporalField field = null; ! if (rangeUnit == MONTHS) { // week-of-month ! field = DAY_OF_MONTH; ! } else if (rangeUnit == YEARS) { // week-of-year ! field = DAY_OF_YEAR; } else { throw new IllegalStateException("unreachable"); } // Offset the ISO DOW by the start of this week int sow = weekDef.getFirstDayOfWeek().getValue(); ! int dow = localizedDayOfWeek(temporal, sow); int offset = startOfWeekOffset(temporal.get(field), dow); ValueRange fieldRange = temporal.range(field); return ValueRange.of(computeWeek(offset, (int) fieldRange.getMinimum()), computeWeek(offset, (int) fieldRange.getMaximum()));