Exemplo n.º 1
0
  /**
   * Converts time field values to UTC as milliseconds.
   *
   * @exception IllegalArgumentException if any fields are invalid.
   */
  protected void computeTime() {

    correctTime();

    // This function takes advantage of the fact that unset fields in
    // the time field list have a value of zero.

    // First, use the year to determine whether to use the Gregorian or the
    // Julian calendar. If the year is not the year of the cutover, this
    // computation will be correct. But if the year is the cutover year,
    // this may be incorrect. In that case, assume the Gregorian calendar,
    // make the computation, and then recompute if the resultant millis
    // indicate the wrong calendar has been assumed.

    // A date such as Oct. 10, 1582 does not exist in a Gregorian calendar
    // with the default changeover of Oct. 15, 1582, since in such a
    // calendar Oct. 4 (Julian) is followed by Oct. 15 (Gregorian).  This
    // algorithm will interpret such a date using the Julian calendar,
    // yielding Oct. 20, 1582 (Gregorian).
    int year = this.fields[YEAR];
    boolean isGregorian = year >= gregorianCutoverYear;
    long julianDay = calculateJulianDay(isGregorian, year);

    // if DAY_OF_WEEK was set more recently than DAY_OF_MONTH and is correct
    // then time is computed using current week and day of week
    if (isSet[DAY_OF_WEEK] && fields[DAY_OF_WEEK] >= SUNDAY && fields[DAY_OF_WEEK] <= SATURDAY) {
      julianDay += fields[DAY_OF_WEEK] - julianDayToDayOfWeek(julianDay);
      fields[DATE] += fields[DAY_OF_WEEK] - julianDayToDayOfWeek(julianDay);
    }

    long millis = julianDayToMillis(julianDay);

    // The following check handles portions of the cutover year BEFORE the
    // cutover itself happens. The check for the julianDate number is for a
    // rare case; it's a hardcoded number, but it's efficient.  The given
    // Julian day number corresponds to Dec 3, 292269055 BC, which
    // corresponds to millis near Long.MIN_VALUE.  The need for the check
    // arises because for extremely negative Julian day numbers, the millis
    // actually overflow to be positive values. Without the check, the
    // initial date is interpreted with the Gregorian calendar, even when
    // the cutover doesn't warrant it.
    if (isGregorian != (millis >= gregorianCutover) && julianDay != -106749550580L) { // See above

      julianDay = calculateJulianDay(!isGregorian, year);
      millis = julianDayToMillis(julianDay);
    }

    // Do the time portion of the conversion.

    int millisInDay = 0;

    // Hours
    // Don't normalize here; let overflow bump into the next period.
    // This is consistent with how we handle other fields.
    millisInDay += this.fields[HOUR_OF_DAY];
    millisInDay *= 60;

    // now get minutes
    millisInDay += this.fields[MINUTE];
    millisInDay *= 60;

    // now get seconds
    millisInDay += this.fields[SECOND];
    millisInDay *= 1000;

    // now get millis
    millisInDay += this.fields[MILLISECOND];

    // Compute the time zone offset and DST offset.  There are two potential
    // ambiguities here.  We'll assume a 2:00 am (wall time) switchover time
    // for discussion purposes here.
    // 1. The transition into DST.  Here, a designated time of 2:00 am - 2:59 am
    //    can be in standard or in DST depending.  However, 2:00 am is an invalid
    //    representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
    //    We assume standard time.
    // 2. The transition out of DST.  Here, a designated time of 1:00 am - 1:59 am
    //    can be in standard or DST.  Both are valid representations (the rep
    //    jumps from 1:59:59 DST to 1:00:00 Std).
    //    Again, we assume standard time.
    // We use the TimeZone object to get the zone offset
    int zoneOffset = getTimeZone().getRawOffset();

    // Now add date and millisInDay together, to make millis contain local wall
    // millis, with no zone or DST adjustments
    millis += millisInDay;

    // Normalize the millisInDay to 0..ONE_DAY-1.  If the millis is out
    // of range, then we must call timeToFields() to recompute our
    // fields.
    int[] normalizedMillisInDay = new int[1];
    floorDivide(millis, (int) ONE_DAY, normalizedMillisInDay);

    // We need to have the month, the day, and the day of the week.
    // Calling timeToFields will compute the MONTH and DATE fields.
    //
    // It's tempting to try to use DAY_OF_WEEK here, if it
    // is set, but we CAN'T.  Even if it's set, it might have
    // been set wrong by the user.  We should rely only on
    // the Julian day number, which has been computed correctly
    // using the disambiguation algorithm above. [LIU]
    int dow = julianDayToDayOfWeek(julianDay);

    // It's tempting to try to use DAY_OF_WEEK here, if it
    // is set, but we CAN'T.  Even if it's set, it might have
    // been set wrong by the user.  We should rely only on
    // the Julian day number, which has been computed correctly
    // using the disambiguation algorithm above. [LIU]
    int dstOffset =
        getTimeZone()
                .getOffset(
                    AD,
                    this.fields[YEAR],
                    this.fields[MONTH],
                    this.fields[DATE],
                    dow,
                    normalizedMillisInDay[0])
            - zoneOffset;
    // Note: Because we pass in wall millisInDay, rather than
    // standard millisInDay, we interpret "1:00 am" on the day
    // of cessation of DST as "1:00 am Std" (assuming the time
    // of cessation is 2:00 am).

    // Store our final computed GMT time, with timezone adjustments.
    time = millis - zoneOffset - dstOffset;
  }