Index: src/test/java/tests/api/java/util/GregorianCalendarTest.java =================================================================== --- src/test/java/tests/api/java/util/GregorianCalendarTest.java (revision 494348) +++ src/test/java/tests/api/java/util/GregorianCalendarTest.java (working copy) @@ -296,6 +296,16 @@ .getActualMaximum(Calendar.HOUR)); assertEquals("Wrong actual maximum value for DAY_OF_WEEK_IN_MONTH", 4, gc6 .getActualMaximum(Calendar.DAY_OF_WEEK_IN_MONTH)); + + + // Regression test for harmony 2954 + Date date = new Date(Date.parse("Jan 15 00:00:01 GMT 2000")); + GregorianCalendar gc = new GregorianCalendar(); + gc.setTimeInMillis(Date.parse("Dec 15 00:00:01 GMT 1582")); + assertEquals(355, gc.getActualMaximum(Calendar.DAY_OF_YEAR)); + gc.setGregorianChange(date); + gc.setTimeInMillis(Date.parse("Jan 16 00:00:01 GMT 2000")); + assertEquals(353, gc.getActualMaximum(Calendar.DAY_OF_YEAR)); } /** Index: src/main/java/java/util/GregorianCalendar.java =================================================================== --- src/main/java/java/util/GregorianCalendar.java (revision 494348) +++ src/main/java/java/util/GregorianCalendar.java (working copy) @@ -74,6 +74,10 @@ private long lastMidnightMillis = 0L; + private int currentYearSkew = 10; + + private int lastYearSkew = 0; + /** * Constructs a new GregorianCalendar initialized to the current date and * time. @@ -796,7 +800,14 @@ } private int daysInYear() { - return isLeapYear(fields[YEAR]) ? 366 : 365; + int daysInYear = isLeapYear(fields[YEAR]) ? 366 : 365; + if (fields[YEAR] == changeYear) { + daysInYear -= currentYearSkew; + } + if (fields[YEAR] == changeYear - 1) { + daysInYear -= lastYearSkew; + } + return daysInYear; } private int daysInYear(boolean leapYear, int month) { @@ -1205,6 +1216,15 @@ julianSkew = ((changeYear - 2000) / 400) + julianError() - ((changeYear - 2000) / 100); isCached = false; + int dayOfYear = cal.get(DAY_OF_YEAR); + if (dayOfYear < julianSkew) { + currentYearSkew = dayOfYear; + lastYearSkew = julianSkew - dayOfYear; + } else { + lastYearSkew = 0; + currentYearSkew = julianSkew; + } + isCached = false; } private void writeObject(ObjectOutputStream stream) throws IOException {