# HG changeset patch # User scolebourne # Date 1397310884 -3600 # Node ID a25d367576e887afae085c14db01895d55143920 # Parent aa920ff150131dea1da66add7e6904724ac951d6 8040058: IsoFields.WEEK_BASED_YEAR adjustInto incorrect and WeekFields.weekOfWeekBasedYear().range incorrect Reviewed-by: lancea, rriggs diff -r aa920ff15013 -r a25d367576e8 jdk/src/share/classes/java/time/temporal/IsoFields.java --- a/jdk/src/share/classes/java/time/temporal/IsoFields.java Fri Apr 18 17:37:13 2014 -0400 +++ b/jdk/src/share/classes/java/time/temporal/IsoFields.java Sat Apr 12 14:54:44 2014 +0100 @@ -535,11 +535,17 @@ if (isSupportedBy(temporal) == false) { throw new UnsupportedTemporalTypeException("Unsupported field: WeekBasedYear"); } - int newVal = range().checkValidIntValue(newValue, WEEK_BASED_YEAR); // strict check + int newWby = range().checkValidIntValue(newValue, WEEK_BASED_YEAR); // strict check LocalDate date = LocalDate.from(temporal); + int dow = date.get(DAY_OF_WEEK); int week = getWeek(date); - date = date.withDayOfYear(180).withYear(newVal).with(WEEK_OF_WEEK_BASED_YEAR, week); - return (R) date.with(date); + if (week == 53 && getWeekRange(newWby) == 52) { + week = 52; + } + LocalDate resolved = LocalDate.of(newWby, 1, 4); // 4th is guaranteed to be in week one + int days = (dow - resolved.get(DAY_OF_WEEK)) + ((week - 1) * 7); + resolved = resolved.plusDays(days); + return (R) temporal.with(resolved); } @Override public String toString() { @@ -577,12 +583,16 @@ private static ValueRange getWeekRange(LocalDate date) { int wby = getWeekBasedYear(date); - date = date.withDayOfYear(1).withYear(wby); + return ValueRange.of(1, getWeekRange(wby)); + } + + private static int getWeekRange(int wby) { + LocalDate date = LocalDate.of(wby, 1, 1); // 53 weeks if standard year starts on Thursday, or Wed in a leap year if (date.getDayOfWeek() == THURSDAY || (date.getDayOfWeek() == WEDNESDAY && date.isLeapYear())) { - return ValueRange.of(1, 53); + return 53; } - return ValueRange.of(1, 52); + return 52; } private static int getWeek(LocalDate date) { diff -r aa920ff15013 -r a25d367576e8 jdk/src/share/classes/java/time/temporal/WeekFields.java --- a/jdk/src/share/classes/java/time/temporal/WeekFields.java Fri Apr 18 17:37:13 2014 -0400 +++ b/jdk/src/share/classes/java/time/temporal/WeekFields.java Sat Apr 12 14:54:44 2014 +0100 @@ -700,7 +700,7 @@ * @see WeekFields#weekOfWeekBasedYear() */ static ComputedDayOfField ofWeekOfWeekBasedYearField(WeekFields weekDef) { - return new ComputedDayOfField("WeekOfWeekBasedYear", weekDef, WEEKS, IsoFields.WEEK_BASED_YEARS, WEEK_OF_YEAR_RANGE); + return new ComputedDayOfField("WeekOfWeekBasedYear", weekDef, WEEKS, IsoFields.WEEK_BASED_YEARS, WEEK_OF_WEEK_BASED_YEAR_RANGE); } /** @@ -753,6 +753,7 @@ 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); + private static final ValueRange WEEK_OF_WEEK_BASED_YEAR_RANGE = ValueRange.of(1, 52, 53); @Override public long getFrom(TemporalAccessor temporal) { diff -r aa920ff15013 -r a25d367576e8 jdk/test/java/time/test/java/time/temporal/TestIsoWeekFields.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/java/time/test/java/time/temporal/TestIsoWeekFields.java Sat Apr 12 14:54:44 2014 +0100 @@ -0,0 +1,280 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package test.java.time.temporal; + +import static java.time.temporal.ChronoField.DAY_OF_WEEK; +import static org.testng.Assert.assertEquals; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.MonthDay; +import java.time.OffsetDateTime; +import java.time.Year; +import java.time.chrono.ThaiBuddhistDate; +import java.time.temporal.ChronoUnit; +import java.time.temporal.IsoFields; +import java.time.temporal.TemporalField; +import java.time.temporal.ValueRange; +import java.time.temporal.WeekFields; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +/** + * Test. + */ +@Test +public class TestIsoWeekFields { + + @DataProvider(name = "fields") + Object[][] data_Fields() { + return new Object[][] { + {IsoFields.WEEK_OF_WEEK_BASED_YEAR, IsoFields.WEEK_BASED_YEAR}, + {WeekFields.ISO.weekOfWeekBasedYear(), WeekFields.ISO.weekBasedYear()}, + }; + } + + //----------------------------------------------------------------------- + // WEEK_OF_WEEK_BASED_YEAR + //----------------------------------------------------------------------- + @Test(dataProvider = "fields") + public void test_WOWBY_basics(TemporalField weekField, TemporalField yearField) { + assertEquals(weekField.isDateBased(), true); + assertEquals(weekField.isTimeBased(), false); + assertEquals(weekField.getBaseUnit(), ChronoUnit.WEEKS); + assertEquals(weekField.getRangeUnit(), IsoFields.WEEK_BASED_YEARS); + } + + @Test(dataProvider = "fields") + public void test_WOWBY_isSupportedBy(TemporalField weekField, TemporalField yearField) { + assertEquals(weekField.isSupportedBy(LocalTime.NOON), false); + assertEquals(weekField.isSupportedBy(MonthDay.of(2, 1)), false); + assertEquals(weekField.isSupportedBy(LocalDate.MIN), true); + assertEquals(weekField.isSupportedBy(OffsetDateTime.MAX), true); + } + + @Test + public void test_WOWBY_isSupportedBy_fieldsDiffer() { + assertEquals(IsoFields.WEEK_OF_WEEK_BASED_YEAR.isSupportedBy(ThaiBuddhistDate.now()), false); + assertEquals(WeekFields.ISO.weekOfWeekBasedYear().isSupportedBy(ThaiBuddhistDate.now()), true); + } + + @Test(dataProvider = "fields") + public void test_WOWBY_range(TemporalField weekField, TemporalField yearField) { + assertEquals(weekField.range(), ValueRange.of(1, 52, 53)); + } + + @Test(dataProvider = "fields") + public void test_WOWBY_rangeRefinedBy(TemporalField weekField, TemporalField yearField) { + assertEquals(weekField.rangeRefinedBy(LocalDate.of(2012, 12, 31)), ValueRange.of(1, 52)); + assertEquals(weekField.rangeRefinedBy(LocalDate.of(2013, 12, 29)), ValueRange.of(1, 52)); + assertEquals(weekField.rangeRefinedBy(LocalDate.of(2013, 12, 30)), ValueRange.of(1, 52)); + assertEquals(weekField.rangeRefinedBy(LocalDate.of(2014, 12, 28)), ValueRange.of(1, 52)); + assertEquals(weekField.rangeRefinedBy(LocalDate.of(2014, 12, 29)), ValueRange.of(1, 53)); + assertEquals(weekField.rangeRefinedBy(LocalDate.of(2016, 1, 3)), ValueRange.of(1, 53)); + assertEquals(weekField.rangeRefinedBy(LocalDate.of(2016, 1, 4)), ValueRange.of(1, 52)); + } + + //----------------------------------------------------------------------- + // WEEK_BASED_YEAR + //----------------------------------------------------------------------- + @Test(dataProvider = "fields") + public void test_WBY_basics(TemporalField weekField, TemporalField yearField) { + assertEquals(yearField.isDateBased(), true); + assertEquals(yearField.isTimeBased(), false); + assertEquals(yearField.getBaseUnit(), IsoFields.WEEK_BASED_YEARS); + assertEquals(yearField.getRangeUnit(), ChronoUnit.FOREVER); + } + + @Test(dataProvider = "fields") + public void test_WBY_isSupportedBy(TemporalField weekField, TemporalField yearField) { + assertEquals(yearField.isSupportedBy(LocalTime.NOON), false); + assertEquals(yearField.isSupportedBy(MonthDay.of(2, 1)), false); + assertEquals(yearField.isSupportedBy(LocalDate.MIN), true); + assertEquals(yearField.isSupportedBy(OffsetDateTime.MAX), true); + } + + @Test + public void test_WBY_isSupportedBy_ISO() { + assertEquals(IsoFields.WEEK_BASED_YEAR.isSupportedBy(ThaiBuddhistDate.now()), false); + } + + @Test(dataProvider = "fields") + public void test_WBY_range(TemporalField weekField, TemporalField yearField) { + assertEquals(yearField.range(), ValueRange.of(Year.MIN_VALUE, Year.MAX_VALUE)); + } + + @Test(dataProvider = "fields") + public void test_WBY_rangeRefinedBy(TemporalField weekField, TemporalField yearField) { + assertEquals(yearField.rangeRefinedBy(LocalDate.of(2012, 12, 31)), ValueRange.of(Year.MIN_VALUE, Year.MAX_VALUE)); + } + + //----------------------------------------------------------------------- + @Test(dataProvider = "fields") + public void test_getFrom(TemporalField weekField, TemporalField yearField) { + // tests every day from 2011 to 2016 inclusive + LocalDate date = LocalDate.of(2011, 1, 3); + int wby = 2011; + int week = 1; + int dow = 1; + for (int i = 1; i <= ((52 + 52 + 52 + 52 + 53 + 52) * 7); i++) { + assertEquals(yearField.getFrom(date), wby); + assertEquals(weekField.getFrom(date), week); + assertEquals(DAY_OF_WEEK.getFrom(date), dow); + if (dow == 7) { + dow = 1; + week++; + } else { + dow++; + } + if (week > wbyLen(wby)) { + week = 1; + wby++; + } + date = date.plusDays(1); + } + assertEquals(yearField.getFrom(date), 2017); + assertEquals(weekField.getFrom(date), 1); + assertEquals(DAY_OF_WEEK.getFrom(date), 1); + } + + @Test(dataProvider = "fields") + public void test_adjustInto_dow(TemporalField weekField, TemporalField yearField) { + // tests every day from 2012 to 2016 inclusive + LocalDate date = LocalDate.of(2012, 1, 2); + int wby = 2012; + int week = 1; + int dow = 1; + for (int i = 1; i <= ((52 + 52 + 52 + 53 + 52) * 7); i++) { + for (int j = 1; j <= 7; j++) { + LocalDate adjusted = DAY_OF_WEEK.adjustInto(date, j); + assertEquals(adjusted.get(DAY_OF_WEEK), j); + assertEquals(adjusted.get(weekField), week); + assertEquals(adjusted.get(yearField), wby); + } + if (dow == 7) { + dow = 1; + week++; + } else { + dow++; + } + if (week > wbyLen(wby)) { + week = 1; + wby++; + } + date = date.plusDays(1); + } + } + + @Test(dataProvider = "fields") + public void test_adjustInto_week(TemporalField weekField, TemporalField yearField) { + // tests every day from 2012 to 2016 inclusive + LocalDate date = LocalDate.of(2012, 1, 2); + int wby = 2012; + int week = 1; + int dow = 1; + for (int i = 1; i <= ((52 + 52 + 52 + 53 + 52) * 7); i++) { + int weeksInYear = (wby == 2015 ? 53 : 52); + for (int j = 1; j <= weeksInYear; j++) { + LocalDate adjusted = weekField.adjustInto(date, j); + assertEquals(adjusted.get(weekField), j); + assertEquals(adjusted.get(DAY_OF_WEEK), dow); + assertEquals(adjusted.get(yearField), wby); + } + if (dow == 7) { + dow = 1; + week++; + } else { + dow++; + } + if (week > wbyLen(wby)) { + week = 1; + wby++; + } + date = date.plusDays(1); + } + } + + @Test(dataProvider = "fields") + public void test_adjustInto_wby(TemporalField weekField, TemporalField yearField) { + // tests every day from 2012 to 2016 inclusive + LocalDate date = LocalDate.of(2012, 1, 2); + int wby = 2012; + int week = 1; + int dow = 1; + for (int i = 1; i <= ((52 + 52 + 52 + 53 + 52) * 7); i++) { + for (int j = 2004; j <= 2015; j++) { + LocalDate adjusted = yearField.adjustInto(date, j); + assertEquals(adjusted.get(yearField), j); + assertEquals(adjusted.get(DAY_OF_WEEK), dow); + assertEquals(adjusted.get(weekField), (week == 53 && wbyLen(j) == 52 ? 52 : week), "" + date + " " + adjusted); + } + if (dow == 7) { + dow = 1; + week++; + } else { + dow++; + } + if (week > wbyLen(wby)) { + week = 1; + wby++; + } + date = date.plusDays(1); + } + } + + @Test(dataProvider = "fields") + public void test_addTo_weekBasedYears(TemporalField weekField, TemporalField yearField) { + // tests every day from 2012 to 2016 inclusive + LocalDate date = LocalDate.of(2012, 1, 2); + int wby = 2012; + int week = 1; + int dow = 1; + for (int i = 1; i <= ((52 + 52 + 52 + 53 + 52) * 7); i++) { + for (int j = -5; j <= 5; j++) { + LocalDate adjusted = IsoFields.WEEK_BASED_YEARS.addTo(date, j); + assertEquals(adjusted.get(yearField), wby + j); + assertEquals(adjusted.get(DAY_OF_WEEK), dow); + assertEquals(adjusted.get(weekField), (week == 53 && wbyLen(wby + j) == 52 ? 52 : week), "" + date + " " + adjusted); + } + if (dow == 7) { + dow = 1; + week++; + } else { + dow++; + } + if (week > wbyLen(wby)) { + week = 1; + wby++; + } + date = date.plusDays(1); + } + } + + private int wbyLen(int wby) { + return (wby == 2004 || wby == 2009 || wby == 2015 || wby == 2020 ? 53 : 52); + } + +}