Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4302563

GregorianCalendor.add(int, int) wrong optimisation

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P4 P4
    • 1.4.0
    • 1.2.2, 1.3.0
    • core-libs
    • beta
    • generic
    • generic



      Name: skT88420 Date: 01/04/2000


      java version "1.2.2"
      Classic VM (build JDK-1.2.2-001, native threads, nojit)

      U implemented an optimisation for the dst correction, but I suspect it's wrong.
      At least it will never optimize, because delta cannot be 0, because there is
      another optimisation that
              if (amount == 0) return; // Do nothing!
      and delta is amount. Therefore
      if (delta != 0) setTimeInMillis(time + dst);
      will always call setTimeInMillis, I suppose u want to check against dst != 0!

      Thanks
          Patrick

      Here I attach the method with the Patch:

          /**
           * Overrides Calendar
           * Date Arithmetic function.
           * Adds the specified (signed) amount of time to the given time field,
           * based on the calendar's rules.
           * @param field the time field.
           * @param amount the amount of date or time to be added to the field.
           * @exception IllegalArgumentException if an unknown field is given.
           */
          public void add(int field, int amount) {
              if (amount == 0) return; // Do nothing!
              complete();

              if (field == YEAR) {
                  int year = this.internalGet(YEAR);
                  if (this.internalGetEra() == AD) {
                      year += amount;
                      if (year > 0)
                          this.set(YEAR, year);
                      else { // year <= 0
                          this.set(YEAR, 1 - year);
                          // if year == 0, you get 1 BC
                          this.set(ERA, BC);
                      }
                  }
                  else { // era == BC
                      year -= amount;
                      if (year > 0)
                          this.set(YEAR, year);
                      else { // year <= 0
                          this.set(YEAR, 1 - year);
                          // if year == 0, you get 1 AD
                          this.set(ERA, AD);
                      }
                  }
                  pinDayOfMonth();
              }
              else if (field == MONTH) {
                  int month = this.internalGet(MONTH) + amount;
                  if (month >= 0) {
                      set(YEAR, internalGet(YEAR) + (month / 12));
                      set(MONTH, (int) (month % 12));
                  }
                  else { // month < 0

                      set(YEAR, internalGet(YEAR) + ((month + 1) / 12) - 1);
                      month %= 12;
                      if (month < 0) month += 12;
                      set(MONTH, JANUARY + month);
                  }
                  pinDayOfMonth();
              }
              else if (field == ERA) {
                  int era = internalGet(ERA) + amount;
                  if (era < 0) era = 0;
                  if (era > 1) era = 1;
                  set(ERA, era);
              }
              else {
                  // We handle most fields here. The algorithm is to add a computed amount
                  // of millis to the current millis. The only wrinkle is with DST -- if
                  // the result of the add operation is to move from DST to Standard, or vice
                  // versa, we need to adjust by an hour forward or back, respectively.
                  // Otherwise you get weird effects in which the hour seems to shift when
                  // you add to the DAY_OF_MONTH field, for instance.

                  // We only adjust the DST for fields larger than an hour. For fields
                  // smaller than an hour, we cannot adjust for DST without causing problems.
                  // for instance, if you add one hour to April 5, 1998, 1:00 AM, in PST,
                  // the time becomes "2:00 AM PDT" (an illegal value), but then the adjustment
                  // sees the change and compensates by subtracting an hour. As a result the
                  // time doesn't advance at all.

                  long delta = amount;
                  boolean adjustDST = true;

                  switch (field) {
                  case WEEK_OF_YEAR:
                  case WEEK_OF_MONTH:
                  case DAY_OF_WEEK_IN_MONTH:
                      delta *= 7 * 24 * 60 * 60 * 1000; // 7 days
                      break;

                  case AM_PM:
                      delta *= 12 * 60 * 60 * 1000; // 12 hrs
                      break;

                  case DATE: // synonym of DAY_OF_MONTH
                  case DAY_OF_YEAR:
                  case DAY_OF_WEEK:
                      delta *= 24 * 60 * 60 * 1000; // 1 day
                      break;

                  case HOUR_OF_DAY:
                  case HOUR:
                      delta *= 60 * 60 * 1000; // 1 hour
                      adjustDST = false;
                      break;

                  case MINUTE:
                      delta *= 60 * 1000; // 1 minute
                      adjustDST = false;
                      break;

                  case SECOND:
                      delta *= 1000; // 1 second
                      adjustDST = false;
                      break;

                  case MILLISECOND:
                      adjustDST = false;
                      break;

                  case ZONE_OFFSET:
                  case DST_OFFSET:
                  default:
                      throw new IllegalArgumentException();
                  }

                  // Save the current DST state.
                  long dst = 0;
                  if (adjustDST) dst = internalGet(DST_OFFSET);

                  setTimeInMillis(time + delta); // Automatically computes fields if necessary

                  if (adjustDST) {
                      // Now do the DST adjustment alluded to above.
                      // Only call setTimeInMillis if necessary, because it's an expensive call.
                      dst -= internalGet(DST_OFFSET);
      // Patch: Optimisation is probably wrong, delta is amount and cannot be 0,suppose u want to
      // check against dst != 0!
      // if (delta != 0) setTimeInMillis(time + dst);
                      if (dst != 0) setTimeInMillis(time + dst);
      //////////////////////////////////////////////////////////////
                  }
              }
          }
      (Review ID: 99410)
      ======================================================================

            okutsu Masayoshi Okutsu
            skonchad Sandeep Konchady
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: