Logo Search packages:      
Sourcecode: icu version File versions  Download package

int32_t Calendar::fieldDifference ( UDate  when,
UCalendarDateFields  field,
UErrorCode status 
) [virtual, inherited]

Return the difference between the given time and the time this calendar object is set to. If this calendar is set before the given time, the returned value will be positive. If this calendar is set after the given time, the returned value will be negative. The field parameter specifies the units of the return value. For example, if fieldDifference(when, Calendar::MONTH) returns 3, then this calendar is set to 3 months before when, and possibly some addition time less than one month.

As a side effect of this call, this calendar is advanced toward when by the given amount. That is, calling this method has the side effect of calling add(field, n), where n is the return value.

Usage: To use this method, call it first with the largest field of interest, then with progressively smaller fields. For example:

 int y = cal->fieldDifference(when, Calendar::YEAR, err);
 int m = cal->fieldDifference(when, Calendar::MONTH, err);
 int d = cal->fieldDifference(when, Calendar::DATE, err);

computes the difference between cal and when in years, months, and days.

Note: fieldDifference() is asymmetrical. That is, in the following code:

 cal->setTime(date1, err);
 int m1 = cal->fieldDifference(date2, Calendar::MONTH, err);
 int d1 = cal->fieldDifference(date2, Calendar::DATE, err);
 cal->setTime(date2, err);
 int m2 = cal->fieldDifference(date1, Calendar::MONTH, err);
 int d2 = cal->fieldDifference(date1, Calendar::DATE, err);

one might expect that m1 == -m2 && d1 == -d2. However, this is not generally the case, because of irregularities in the underlying calendar system (e.g., the Gregorian calendar has a varying number of days per month).

Parameters:
when the date to compare this calendar's time to
field the field in which to compute the result
status Output param set to success/failure code on exit. If any value previously set in the time field is invalid, this will be set to an error status.
Returns:
the difference, either positive or negative, between this calendar's time and when, in terms of field. ICU 2.6.

Definition at line 1889 of file calendar.cpp.

References Calendar::getTimeInMillis(), Calendar::setTimeInMillis(), U_FAILURE, U_ILLEGAL_ARGUMENT_ERROR, and U_SUCCESS.

                                                                                           {
    if (U_FAILURE(ec)) return 0;
    int32_t min = 0;
    double startMs = getTimeInMillis(ec);
    // Always add from the start millis.  This accomodates
    // operations like adding years from February 29, 2000 up to
    // February 29, 2004.  If 1, 1, 1, 1 is added to the year
    // field, the DOM gets pinned to 28 and stays there, giving an
    // incorrect DOM difference of 1.  We have to add 1, reset, 2,
    // reset, 3, reset, 4.
    if (startMs < targetMs) {
        int32_t max = 1;
        // Find a value that is too large
        while (U_SUCCESS(ec)) {
            setTimeInMillis(startMs, ec);
            add(field, max, ec);
            double ms = getTimeInMillis(ec);
            if (ms == targetMs) {
                return max;
            } else if (ms > targetMs) {
                break;
            } else {
                max <<= 1;
                if (max < 0) {
                    // Field difference too large to fit into int32_t
#if defined (U_DEBUG_CAL)
                    fprintf(stderr, "%s:%d: ILLEGAL ARG because field %s's max too large for int32_t\n",
                        __FILE__, __LINE__, fldName(field));
#endif
                    ec = U_ILLEGAL_ARGUMENT_ERROR;
                }
            }
        }
        // Do a binary search
        while ((max - min) > 1 && U_SUCCESS(ec)) {
            int32_t t = (min + max) / 2;
            setTimeInMillis(startMs, ec);
            add(field, t, ec);
            double ms = getTimeInMillis(ec);
            if (ms == targetMs) {
                return t;
            } else if (ms > targetMs) {
                max = t;
            } else {
                min = t;
            }
        }
    } else if (startMs > targetMs) {
        int32_t max = -1;
        // Find a value that is too small
        while (U_SUCCESS(ec)) {
            setTimeInMillis(startMs, ec);
            add(field, max, ec);
            double ms = getTimeInMillis(ec);
            if (ms == targetMs) {
                return max;
            } else if (ms < targetMs) {
                break;
            } else {
                max <<= 1;
                if (max == 0) {
                    // Field difference too large to fit into int32_t
#if defined (U_DEBUG_CAL)
                    fprintf(stderr, "%s:%d: ILLEGAL ARG because field %s's max too large for int32_t\n",
                        __FILE__, __LINE__, fldName(field));
#endif
                    ec = U_ILLEGAL_ARGUMENT_ERROR;
                }
            }
        }
        // Do a binary search
        while ((min - max) > 1 && U_SUCCESS(ec)) {
            int32_t t = (min + max) / 2;
            setTimeInMillis(startMs, ec);
            add(field, t, ec);
            double ms = getTimeInMillis(ec);
            if (ms == targetMs) {
                return t;
            } else if (ms < targetMs) {
                max = t;
            } else {
                min = t;
            }
        }
    }
    // Set calendar to end point
    setTimeInMillis(startMs, ec);
    add(field, min, ec);

    /* Test for buffer overflows */
    if(U_FAILURE(ec)) {
        return 0;
    }
    return min;
}


Generated by  Doxygen 1.6.0   Back to index