JDK-4147269 : java.util.GregorianCalendar.computeTime() works wrong when lenient is false
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util:i18n
  • Affected Version: 1.2.0
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: solaris_2.5
  • CPU: sparc
  • Submitted: 1998-06-10
  • Updated: 2003-09-29
  • Resolved: 2003-09-29
Related Reports
Duplicate :  
Relates :  
Description

Name: dfC67450			Date: 06/10/98



java.util.GregorianCalendar.computeTime() does not throw IllegalArgumentException
when lenient is set to false and some fields have been set to illegal value.
The list of fields the method fails with is: WEEK_OF_YEAR, WEEK_OF_MONTH, DAY_OF_YEAR, 
DAY_OF_WEEK_IN_MONTH.

Javadoc says about GregorianCalendar.computeTime:
    
     Converts time field values to UTC as milliseconds.
     exception: IllegalArgumentException if any fields are invalid.
     
Javadoc says about Calendar.setLenient:

     Specify whether or not date/time interpretation is to be lenient.  With
     lenient interpretation, a date such as "February 942, 1996" will be
     treated as being equivalent to the 941st day after February 1, 1996.
     With strict interpretation, such dates will cause an exception to be
     thrown.

Here is the test demonstrating the bug:

-----------------Test.java------------------------
import java.util.*;

public class Test {
  public static void main (String args[]){


    boolean passed = true;
    GregorianCalendarTest calendar = new GregorianCalendarTest();
    calendar.setLenient(false);
    Date date = (new GregorianCalendar(1996,0,3)).getTime();
    for (int field = 0; field < Calendar.FIELD_COUNT; field++) {
      calendar.setTime(date);
      int max = calendar.getActualMaximum(field);
      int value = max+1;
      calendar.set(field, value); 
      try {
          calendar.computeTime(); // call method under test
          System.out.println("Test failed with field " + fieldName[field]);  
          System.out.println("  date before:  " + date);
          System.out.println("  date after:   " + calendar.getTime());
          System.out.println("  value: " + value + "  (max = " + max +")");
          passed = false;
       } catch (IllegalArgumentException e) {
       } 
     }

    if (passed)  System.out.println("Test passed");
  }

  static final String[] fieldName = {
          "ERA", 
          "YEAR", 
          "MONTH", 
          "WEEK_OF_YEAR", 
          "WEEK_OF_MONTH", 
          "DAY_OF_MONTH", 
          "DAY_OF_YEAR", 
          "DAY_OF_WEEK", 
          "DAY_OF_WEEK_IN_MONTH", 
          "AM_PM", 
          "HOUR", 
          "HOUR_OF_DAY", 
          "MINUTE", 
          "SECOND", 
          "MILLISECOND", 
          "ZONE_OFFSET", 
          "DST_OFFSET"
  };


} 

class GregorianCalendarTest extends GregorianCalendar { 
         // access to protected method

    public GregorianCalendarTest(int year, int month, int day) {
      super(year, month, day);
    }
    public GregorianCalendarTest() {
      super();
    }
    public void computeTime() {
       super.computeTime();
    }

}
---------Output from the test---------------------
Test failed with field WEEK_OF_YEAR
  date before:  Wed Jan 03 00:00:00 GMT+03:00 1996
  date after:   Wed Jan 01 00:00:00 GMT+03:00 1997
  value: 53  (max = 52)
Test failed with field WEEK_OF_MONTH
  date before:  Wed Jan 03 00:00:00 GMT+03:00 1996
  date after:   Wed Feb 07 00:00:00 GMT+03:00 1996
  value: 6  (max = 5)
Test failed with field DAY_OF_YEAR
  date before:  Wed Jan 03 00:00:00 GMT+03:00 1996
  date after:   Wed Jan 01 00:00:00 GMT+03:00 1997
  value: 367  (max = 366)
Test failed with field DAY_OF_WEEK_IN_MONTH
  date before:  Wed Jan 03 00:00:00 GMT+03:00 1996
  date after:   Wed Feb 07 00:00:00 GMT+03:00 1996
  value: 6  (max = 5)
-------------------------------------------------

======================================================================

Comments
PUBLIC COMMENTS If the proposed change is made, then 1.1 and 1.2 will behave inconsistently. The underlying reason is that 1.1 does not have a notion of "actual maximum" (that's new 1.2 API), so it can never implement the proposed change. This will mean applets and applications that work correctly with 1.1 will break when run against 1.2 (previously valid field values will become invalid). This violates the upward compatibility principle for user code; in general, changes that will break existing Java code are prohibited. For this reason, this bug is closed.
10-06-2004

EVALUATION fix involves changing the logic in one if() statement in the validateFields method of GregorianCalendar. REGRESSION TEST added to CalendarRegression.java laura.werner@eng 1998-07-09 The test from description still fails. So I reopen this bug. ###@###.### 1998-09-30 I believe this bug should not be reopened. The test in the bug report fails because the test expects the lenient mode to check against getActualMaximum(). This check is too slow, since it generally involves repeated calendar calculations. The GregorianCalendar validation code therefore uses getMaximum() to validate non-lenient input. To confirm this, modify the test to call getMaximum(), not getActualMaximum(). alan.liu@eng 1998-09-30 Note: If the proposed change is made, then 1.1 and 1.2 will behave inconsistently. The underlying reason is that 1.1 does not have a notion of "actual maximum" (that's new 1.2 API), so it can never implement the proposed change. This will mean applets and applications that work correctly with 1.1 will break when run against 1.2 (previously valid field values will become invalid). This violates the upward compatibility principle for user code; in general, changes that will break existing Java code are prohibited. For this reason, this bug should be closed will not fix. alan.liu@eng 1999-03-17 Reopned this bug to be fixed as a duplicate of 4266783. ###@###.### 2003-09-29
17-03-1999