Exemplo n.º 1
0
void HebrewCalendar::validateField(UCalendarDateFields field, UErrorCode &status) {
    if (field == UCAL_MONTH && !isLeapYear(handleGetExtendedYear()) && internalGet(UCAL_MONTH) == ADAR_1) {
        status = U_ILLEGAL_ARGUMENT_ERROR;
        return;
    }
    Calendar::validateField(field, status);
}
Exemplo n.º 2
0
void BuddhistCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status)
{
    GregorianCalendar::handleComputeFields(julianDay, status);
    int32_t y = internalGet(UCAL_EXTENDED_YEAR) - kBuddhistEraStart;
    internalSet(UCAL_ERA, 0);
    internalSet(UCAL_YEAR, y);
}
Exemplo n.º 3
0
int32_t
CopticCalendar::handleGetExtendedYear()
{
    int32_t eyear;
    if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
        eyear = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
    } else {
        // The year defaults to the epoch start, the era to CE
        int32_t era = internalGet(UCAL_ERA, CE);
        if (era == BCE) {
            eyear = 1 - internalGet(UCAL_YEAR, 1); // Convert to extended year
        } else {
            eyear = internalGet(UCAL_YEAR, 1); // Default to year 1
        }
    }
    return eyear;
}
Exemplo n.º 4
0
int32_t
BuddhistCalendar::monthLength(int32_t month) const
{
    UErrorCode status = U_ZERO_ERROR;
    int32_t year = internalGet(UCAL_YEAR);
    // ignore era
    return GregorianCalendar::monthLength(month, getGregorianYear(status));
}
Exemplo n.º 5
0
/**
 * Return the Julian day number of day before the first day of the
 * given month in the given extended year.
 *
 * <p>Note: This method reads the IS_LEAP_MONTH field to determine
 * whether the given month is a leap month.
 * @param eyear the extended year
 * @param month the zero-based month.  The month is also determined
 * by reading the IS_LEAP_MONTH field.
 * @return the Julian day number of the day before the first
 * day of the given month and year
 * @stable ICU 2.8
 */
int32_t ChineseCalendar::handleComputeMonthStart(int32_t eyear, int32_t month, UBool useMonth) const {

    ChineseCalendar *nonConstThis = (ChineseCalendar*)this; // cast away const

    // If the month is out of range, adjust it into range, and
    // modify the extended year value accordingly.
    if (month < 0 || month > 11) {
        double m = month;
        eyear += (int32_t)ClockMath::floorDivide(m, 12.0, m);
        month = (int32_t)m;
    }

    int32_t gyear = eyear + fEpochYear - 1; // Gregorian year
    int32_t theNewYear = newYear(gyear);
    int32_t newMoon = newMoonNear(theNewYear + month * 29, TRUE);

    int32_t julianDay = newMoon + kEpochStartAsJulianDay;

    // Save fields for later restoration
    int32_t saveMonth = internalGet(UCAL_MONTH);
    int32_t saveIsLeapMonth = internalGet(UCAL_IS_LEAP_MONTH);

    // Ignore IS_LEAP_MONTH field if useMonth is false
    int32_t isLeapMonth = useMonth ? saveIsLeapMonth : 0;

    UErrorCode status = U_ZERO_ERROR;
    nonConstThis->computeGregorianFields(julianDay, status);
    if (U_FAILURE(status))
        return 0;

    // This will modify the MONTH and IS_LEAP_MONTH fields (only)
    nonConstThis->computeChineseFields(newMoon, getGregorianYear(),
                         getGregorianMonth(), FALSE);

    if (month != internalGet(UCAL_MONTH) ||
        isLeapMonth != internalGet(UCAL_IS_LEAP_MONTH)) {
        newMoon = newMoonNear(newMoon + SYNODIC_GAP, TRUE);
        julianDay = newMoon + kEpochStartAsJulianDay;
    }

    nonConstThis->internalSet(UCAL_MONTH, saveMonth);
    nonConstThis->internalSet(UCAL_IS_LEAP_MONTH, saveIsLeapMonth);

    return julianDay - 1;
}
Exemplo n.º 6
0
int32_t GregorianCalendar::handleGetExtendedYearFromWeekFields(int32_t yearWoy, int32_t woy)
{
    // convert year to extended form
    int32_t era = internalGet(UCAL_ERA, AD);
    if(era == BC) {
        yearWoy = 1 - yearWoy;
    }
    return Calendar::handleGetExtendedYearFromWeekFields(yearWoy, woy);
}
Exemplo n.º 7
0
int32_t JapaneseCalendar::handleGetExtendedYear()
{
    // EXTENDED_YEAR in JapaneseCalendar is a Gregorian year
    // The default value of EXTENDED_YEAR is 1970 (Showa 45)
    int32_t year;

    if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR &&
            newerField(UCAL_EXTENDED_YEAR, UCAL_ERA) == UCAL_EXTENDED_YEAR)
    {
        year = internalGet(UCAL_EXTENDED_YEAR, kGregorianEpoch);
    }
    else
    {
        // Subtract one because year starts at 1
        year = internalGet(UCAL_YEAR) + kEraInfo[internalGetEra()].year - 1;
    }
    return year;
}
Exemplo n.º 8
0
int32_t TaiwanCalendar::handleGetExtendedYear()
{
    // EXTENDED_YEAR in TaiwanCalendar is a Gregorian year
    // The default value of EXTENDED_YEAR is 1970 (Minguo 59)
    int32_t year = kGregorianEpoch;

    if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR
        && newerField(UCAL_EXTENDED_YEAR, UCAL_ERA) == UCAL_EXTENDED_YEAR) {
        year = internalGet(UCAL_EXTENDED_YEAR, kGregorianEpoch);
    } else {
        int32_t era = internalGet(UCAL_ERA, MINGUO);
        if(era == MINGUO) {
            year =     internalGet(UCAL_YEAR, 1) + kTaiwanEraStart;
        } else if(era == BEFORE_MINGUO) {
            year = 1 - internalGet(UCAL_YEAR, 1) + kTaiwanEraStart;
        }
    }
    return year;
}
Exemplo n.º 9
0
UBool
GregorianCalendar::inDaylightTime(UErrorCode& status) const
{
    if (U_FAILURE(status) || !getTimeZone().useDaylightTime()) 
        return FALSE;

    // Force an update of the state of the Calendar.
    ((GregorianCalendar*)this)->complete(status); // cast away const

    return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : FALSE);
}
Exemplo n.º 10
0
bool SkBitSet::orBits(const SkBitSet& source) {
    if (fBitCount != source.fBitCount) {
        return false;
    }
    uint32_t* targetBitmap = internalGet(0);
    uint32_t* sourceBitmap = source.internalGet(0);
    for (size_t i = 0; i < fDwordCount; ++i) {
        targetBitmap[i] |= sourceBitmap[i];
    }
    return true;
}
Exemplo n.º 11
0
void BuddhistCalendar::timeToFields(UDate theTime, UBool quick, UErrorCode& status)
{
    //Calendar::timeToFields(theTime, quick, status);

    int32_t era = internalGet(UCAL_ERA);
    int32_t year = internalGet(UCAL_YEAR);

    if(era == GregorianCalendar::BC) {
        year = 1-year;
        era = BuddhistCalendar::BE;
    } else if(era == GregorianCalendar::AD) {
        era = BuddhistCalendar::BE;
    } else {
        status = U_INTERNAL_PROGRAM_ERROR;
    }

    year = year - kBuddhistEraStart;

    internalSet(UCAL_ERA, era);
    internalSet(UCAL_YEAR, year);
}
Exemplo n.º 12
0
UBool
IslamicCalendar::inDaylightTime(UErrorCode & status) const
{
	// copied from GregorianCalendar
	if (U_FAILURE(status) || (&(getTimeZone()) == NULL && !getTimeZone().useDaylightTime()))
	{ return FALSE; }

	// Force an update of the state of the Calendar.
	((IslamicCalendar *)this)->complete(status); // cast away const

	return (UBool)(U_SUCCESS(status) ? (internalGet(UCAL_DST_OFFSET) != 0) : FALSE);
}
Exemplo n.º 13
0
void TaiwanCalendar::handleComputeFields(int32_t julianDay, UErrorCode& status)
{
    GregorianCalendar::handleComputeFields(julianDay, status);
    int32_t y = internalGet(UCAL_EXTENDED_YEAR) - kTaiwanEraStart;
    if(y>0) {
        internalSet(UCAL_ERA, MINGUO);
        internalSet(UCAL_YEAR, y);
    } else {
        internalSet(UCAL_ERA, BEFORE_MINGUO);
        internalSet(UCAL_YEAR, 1-y);
    }
}
Exemplo n.º 14
0
int32_t
EthiopicCalendar::handleGetExtendedYear()
{
    // Ethiopic calendar uses EXTENDED_YEAR aligned to
    // Amelete Hihret year always.
    int32_t eyear;
    if (newerField(UCAL_EXTENDED_YEAR, UCAL_YEAR) == UCAL_EXTENDED_YEAR) {
        eyear = internalGet(UCAL_EXTENDED_YEAR, 1); // Default to year 1
    } else if (isAmeteAlemEra()) {
        eyear = internalGet(UCAL_YEAR, 1 + AMETE_MIHRET_DELTA)
            - AMETE_MIHRET_DELTA; // Default to year 1 of Amelete Mihret
    } else {
        // The year defaults to the epoch start, the era to AMETE_MIHRET
        int32_t era = internalGet(UCAL_ERA, AMETE_MIHRET);
        if (era == AMETE_MIHRET) {
            eyear = internalGet(UCAL_YEAR, 1); // Default to year 1
        } else {
            eyear = internalGet(UCAL_YEAR, 1) - AMETE_MIHRET_DELTA;
        }
    }
    return eyear;
}
Exemplo n.º 15
0
UBool
GregorianCalendar::validateFields() const
{
    for (int32_t field = 0; field < UCAL_FIELD_COUNT; field++) {
        // Ignore DATE and DAY_OF_YEAR which are handled below
        if (field != UCAL_DATE &&
            field != UCAL_DAY_OF_YEAR &&
            isSet((UCalendarDateFields)field) &&
            ! boundsCheck(internalGet((UCalendarDateFields)field), (UCalendarDateFields)field))
            return FALSE;
    }

    // Values differ in Least-Maximum and Maximum should be handled
    // specially.
    if (isSet(UCAL_DATE)) {
        int32_t date = internalGet(UCAL_DATE);
        if (date < getMinimum(UCAL_DATE) ||
            date > monthLength(internalGet(UCAL_MONTH))) {
                return FALSE;
            }
    }

    if (isSet(UCAL_DAY_OF_YEAR)) {
        int32_t days = internalGet(UCAL_DAY_OF_YEAR);
        if (days < 1 || days > yearLength()) {
            return FALSE;
        }
    }

    // Handle DAY_OF_WEEK_IN_MONTH, which must not have the value zero.
    // We've checked against minimum and maximum above already.
    if (isSet(UCAL_DAY_OF_WEEK_IN_MONTH) &&
        0 == internalGet(UCAL_DAY_OF_WEEK_IN_MONTH)) {
            return FALSE;
        }

        return TRUE;
}
Exemplo n.º 16
0
int32_t GregorianCalendar::handleGetExtendedYear() {
    // the year to return
    int32_t year = kEpochYear;

    // year field to use
    int32_t yearField = UCAL_EXTENDED_YEAR;

    // There are three separate fields which could be used to
    // derive the proper year.  Use the one most recently set.
    if (fStamp[yearField] < fStamp[UCAL_YEAR])
        yearField = UCAL_YEAR;
    if (fStamp[yearField] < fStamp[UCAL_YEAR_WOY])
        yearField = UCAL_YEAR_WOY;

    // based on the "best" year field, get the year
    switch(yearField) {
    case UCAL_EXTENDED_YEAR:
        year = internalGet(UCAL_EXTENDED_YEAR, kEpochYear);
        break;

    case UCAL_YEAR:
        {
            // The year defaults to the epoch start, the era to AD
            int32_t era = internalGet(UCAL_ERA, AD);
            if (era == BC) {
                year = 1 - internalGet(UCAL_YEAR, 1); // Convert to extended year
            } else {
                year = internalGet(UCAL_YEAR, kEpochYear);
            }
        }
        break;

    case UCAL_YEAR_WOY:
        year = handleGetExtendedYearFromWeekFields(internalGet(UCAL_YEAR_WOY), internalGet(UCAL_WEEK_OF_YEAR));
#if defined (U_DEBUG_CAL)
        //    if(internalGet(UCAL_YEAR_WOY) != year) {
        fprintf(stderr, "%s:%d: hGEYFWF[%d,%d] ->  %d\n", 
            __FILE__, __LINE__,internalGet(UCAL_YEAR_WOY),internalGet(UCAL_WEEK_OF_YEAR),year);
        //}
#endif
        break;

    default:
        year = kEpochYear;
    }
    return year;
}
Exemplo n.º 17
0
void BuddhistCalendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status)
{
    if (U_FAILURE(status)) 
        return;

    if (amount == 0) 
        return;   // Do nothing!
    
    if(field == UCAL_YEAR /* || field == UCAL_YEAR_WOY */) {
        int32_t year = internalGet(field);
        int32_t era = internalGetEra();

        year += amount;
        
        set(field,year);
        pinDayOfMonth();
    } else {
      GregorianCalendar::add(field,amount,status);
    }
}
Exemplo n.º 18
0
int32_t
GregorianCalendar::yearLength() const
{
    return isLeapYear(internalGet(UCAL_YEAR)) ? 366 : 365;
}
Exemplo n.º 19
0
int32_t BuddhistCalendar::internalGetEra() const
{
    return isSet(UCAL_ERA) ? internalGet(UCAL_ERA) : BE;  
}
Exemplo n.º 20
0
bool SkBitSet::isBitSet(int index) const {
    uint32_t mask = 1 << (index % 32);
    return 0 != (*internalGet(index) & mask);
}
Exemplo n.º 21
0
/**
* Return the ERA.  We need a special method for this because the
* default ERA is AD, but a zero (unset) ERA is BC.
*/
int32_t
GregorianCalendar::internalGetEra() const {
    return isSet(UCAL_ERA) ? internalGet(UCAL_ERA) : (int32_t)AD;
}
Exemplo n.º 22
0
void JapaneseCalendar::handleComputeFields(int32_t julianDay, UErrorCode & status)
{
    //Calendar::timeToFields(theTime, quick, status);
    GregorianCalendar::handleComputeFields(julianDay, status);
    int32_t year = internalGet(UCAL_EXTENDED_YEAR); // Gregorian year

    int32_t low = 0;

    // Short circuit for recent years.  Most modern computations will
    // occur in the current era and won't require the binary search.
    // Note that if the year is == the current era year, then we use
    // the binary search to handle the month/dom comparison.
#ifdef U_DEBUG_JCAL
    fprintf(stderr, "==  %d \n", year);
#endif

    if (year > kEraInfo[kCurrentEra].year)
    {
        low = kCurrentEra;
#ifdef U_DEBUG_JCAL
        fprintf(stderr, " low=%d (special)\n", low);
#endif
    }
    else
    {
        // Binary search
        int32_t high = kEraCount;

#ifdef U_DEBUG_JCAL
        fprintf(stderr, " high=%d\n", high);
#endif
        while (low < high - 1)
        {
            int32_t i = (low + high) / 2;
            int32_t diff = year - kEraInfo[i].year;

#ifdef U_DEBUG_JCAL
            fprintf(stderr, "  d=%d   low=%d, high=%d. Considering %d:M%d D%d Y%d. { we are ?:M%d D%d Y%d }\n",
                    diff, low, high, i, kEraInfo[i].month - 1, kEraInfo[i].day,  kEraInfo[i].year, internalGet(UCAL_MONTH),
                    internalGet(UCAL_DATE), year);
#endif

            // If years are the same, then compare the months, and if those
            // are the same, compare days of month.  In the ERAS array
            // months are 1-based for easier maintenance.
            if (diff == 0)
            {
                diff = internalGet(UCAL_MONTH) - (kEraInfo[i].month - 1);
#ifdef U_DEBUG_JCAL
                fprintf(stderr, "diff now %d (M)  = %d - %d - 1\n", diff, internalGet(UCAL_MONTH), kEraInfo[i].month);
#endif
                if (diff == 0)
                {
                    diff = internalGet(UCAL_DATE) - kEraInfo[i].day;
#ifdef U_DEBUG_JCAL
                    fprintf(stderr, "diff now %d (D)\n", diff);
#endif
                }
            }
            if (diff >= 0)
            {
                low = i;
            }
            else
            {
                high = i;
            }
#ifdef U_DEBUG_JCAL
            fprintf(stderr, ". low=%d, high=%d, i=%d, diff=%d.. %d\n", low, high, i, diff, year);
#endif

        }
    }

#ifdef U_DEBUG_JCAL
    fprintf(stderr, "  low[era]=%d,.. %d\n", low, year);
#endif
    // Now we've found the last era that starts before this date, so
    // adjust the year to count from the start of that era.  Note that
    // all dates before the first era will fall into the first era by
    // the algorithm.

    internalSet(UCAL_ERA, low);
    internalSet(UCAL_YEAR, year - kEraInfo[low].year + 1);
#ifdef U_DEBUG_JCAL
    fprintf(stderr, "  Set ERA=%d, year=%d\n", low, year - kEraInfo[low].year + 1);
#endif

}
Exemplo n.º 23
0
int32_t
GregorianCalendar::monthLength(int32_t month) const
{
    int32_t year = internalGet(UCAL_EXTENDED_YEAR);
    return handleGetMonthLength(year, month);
}
Exemplo n.º 24
0
int32_t JapaneseCalendar::internalGetEra() const
{
    return internalGet(UCAL_ERA, kCurrentEra);
}
Exemplo n.º 25
0
void
GregorianCalendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& status)
{
    if((amount == 0) || U_FAILURE(status)) {
        return;
    }

    // J81 processing. (gregorian cutover)
    UBool inCutoverMonth = FALSE;
    int32_t cMonthLen=0; // 'c' for cutover; in days
    int32_t cDayOfMonth=0; // no discontinuity: [0, cMonthLen)
    double cMonthStart=0.0; // in ms

    // Common code - see if we're in the cutover month of the cutover year
    if(get(UCAL_EXTENDED_YEAR, status) == fGregorianCutoverYear) {
        switch (field) {
        case UCAL_DAY_OF_MONTH:
        case UCAL_WEEK_OF_MONTH:
            {
                int32_t max = monthLength(internalGet(UCAL_MONTH));
                UDate t = internalGetTime();
                // We subtract 1 from the DAY_OF_MONTH to make it zero-based, and an
                // additional 10 if we are after the cutover. Thus the monthStart
                // value will be correct iff we actually are in the cutover month.
                cDayOfMonth = internalGet(UCAL_DAY_OF_MONTH) - ((t >= fGregorianCutover) ? 10 : 0);
                cMonthStart = t - ((cDayOfMonth - 1) * kOneDay);
                // A month containing the cutover is 10 days shorter.
                if ((cMonthStart < fGregorianCutover) &&
                    (cMonthStart + (cMonthLen=(max-10))*kOneDay >= fGregorianCutover)) {
                        inCutoverMonth = TRUE;
                    }
            }
        default:
            ;
        }
    }

    switch (field) {
    case UCAL_WEEK_OF_YEAR: {
        // Unlike WEEK_OF_MONTH, WEEK_OF_YEAR never shifts the day of the
        // week.  Also, rolling the week of the year can have seemingly
        // strange effects simply because the year of the week of year
        // may be different from the calendar year.  For example, the
        // date Dec 28, 1997 is the first day of week 1 of 1998 (if
        // weeks start on Sunday and the minimal days in first week is
        // <= 3).
        int32_t woy = get(UCAL_WEEK_OF_YEAR, status);
        // Get the ISO year, which matches the week of year.  This
        // may be one year before or after the calendar year.
        int32_t isoYear = get(UCAL_YEAR_WOY, status);
        int32_t isoDoy = internalGet(UCAL_DAY_OF_YEAR);
        if (internalGet(UCAL_MONTH) == UCAL_JANUARY) {
            if (woy >= 52) {
                isoDoy += handleGetYearLength(isoYear);
            }
        } else {
            if (woy == 1) {
                isoDoy -= handleGetYearLength(isoYear - 1);
            }
        }
        woy += amount;
        // Do fast checks to avoid unnecessary computation:
        if (woy < 1 || woy > 52) {
            // Determine the last week of the ISO year.
            // We do this using the standard formula we use
            // everywhere in this file.  If we can see that the
            // days at the end of the year are going to fall into
            // week 1 of the next year, we drop the last week by
            // subtracting 7 from the last day of the year.
            int32_t lastDoy = handleGetYearLength(isoYear);
            int32_t lastRelDow = (lastDoy - isoDoy + internalGet(UCAL_DAY_OF_WEEK) -
                getFirstDayOfWeek()) % 7;
            if (lastRelDow < 0) lastRelDow += 7;
            if ((6 - lastRelDow) >= getMinimalDaysInFirstWeek()) lastDoy -= 7;
            int32_t lastWoy = weekNumber(lastDoy, lastRelDow + 1);
            woy = ((woy + lastWoy - 1) % lastWoy) + 1;
        }
        set(UCAL_WEEK_OF_YEAR, woy);
        set(UCAL_YEAR_WOY,isoYear);
        return;
                            }

    case UCAL_DAY_OF_MONTH:
        if( !inCutoverMonth ) { 
            Calendar::roll(field, amount, status);
            return;
        } else {
            // [j81] 1582 special case for DOM
            // The default computation works except when the current month
            // contains the Gregorian cutover.  We handle this special case
            // here.  [j81 - aliu]
            double monthLen = cMonthLen * kOneDay;
            double msIntoMonth = uprv_fmod(internalGetTime() - cMonthStart +
                amount * kOneDay, monthLen);
            if (msIntoMonth < 0) {
                msIntoMonth += monthLen;
            }
#if defined (U_DEBUG_CAL)
            fprintf(stderr, "%s:%d: roll DOM %d  -> %.0lf ms  \n", 
                __FILE__, __LINE__,amount, cMonthLen, cMonthStart+msIntoMonth);
#endif
            setTimeInMillis(cMonthStart + msIntoMonth, status);
            return;
        }

    case UCAL_WEEK_OF_MONTH:
        if( !inCutoverMonth ) { 
            Calendar::roll(field, amount, status);
            return;
        } else {
#if defined (U_DEBUG_CAL)
            fprintf(stderr, "%s:%d: roll WOM %d ??????????????????? \n", 
                __FILE__, __LINE__,amount);
#endif
            // NOTE: following copied from  the old
            //     GregorianCalendar::roll( WEEK_OF_MONTH )  code 

            // This is tricky, because during the roll we may have to shift
            // to a different day of the week.  For example:

            //    s  m  t  w  r  f  s
            //          1  2  3  4  5
            //    6  7  8  9 10 11 12

            // When rolling from the 6th or 7th back one week, we go to the
            // 1st (assuming that the first partial week counts).  The same
            // thing happens at the end of the month.

            // The other tricky thing is that we have to figure out whether
            // the first partial week actually counts or not, based on the
            // minimal first days in the week.  And we have to use the
            // correct first day of the week to delineate the week
            // boundaries.

            // Here's our algorithm.  First, we find the real boundaries of
            // the month.  Then we discard the first partial week if it
            // doesn't count in this locale.  Then we fill in the ends with
            // phantom days, so that the first partial week and the last
            // partial week are full weeks.  We then have a nice square
            // block of weeks.  We do the usual rolling within this block,
            // as is done elsewhere in this method.  If we wind up on one of
            // the phantom days that we added, we recognize this and pin to
            // the first or the last day of the month.  Easy, eh?

            // Another wrinkle: To fix jitterbug 81, we have to make all this
            // work in the oddball month containing the Gregorian cutover.
            // This month is 10 days shorter than usual, and also contains
            // a discontinuity in the days; e.g., the default cutover month
            // is Oct 1582, and goes from day of month 4 to day of month 15.

            // Normalize the DAY_OF_WEEK so that 0 is the first day of the week
            // in this locale.  We have dow in 0..6.
            int32_t dow = internalGet(UCAL_DAY_OF_WEEK) - getFirstDayOfWeek();
            if (dow < 0) 
                dow += 7;

            // Find the day of month, compensating for cutover discontinuity.
            int32_t dom = cDayOfMonth;

            // Find the day of the week (normalized for locale) for the first
            // of the month.
            int32_t fdm = (dow - dom + 1) % 7;
            if (fdm < 0) 
                fdm += 7;

            // Get the first day of the first full week of the month,
            // including phantom days, if any.  Figure out if the first week
            // counts or not; if it counts, then fill in phantom days.  If
            // not, advance to the first real full week (skip the partial week).
            int32_t start;
            if ((7 - fdm) < getMinimalDaysInFirstWeek())
                start = 8 - fdm; // Skip the first partial week
            else
                start = 1 - fdm; // This may be zero or negative

            // Get the day of the week (normalized for locale) for the last
            // day of the month.
            int32_t monthLen = cMonthLen;
            int32_t ldm = (monthLen - dom + dow) % 7;
            // We know monthLen >= DAY_OF_MONTH so we skip the += 7 step here.

            // Get the limit day for the blocked-off rectangular month; that
            // is, the day which is one past the last day of the month,
            // after the month has already been filled in with phantom days
            // to fill out the last week.  This day has a normalized DOW of 0.
            int32_t limit = monthLen + 7 - ldm;

            // Now roll between start and (limit - 1).
            int32_t gap = limit - start;
            int32_t newDom = (dom + amount*7 - start) % gap;
            if (newDom < 0) 
                newDom += gap;
            newDom += start;

            // Finally, pin to the real start and end of the month.
            if (newDom < 1) 
                newDom = 1;
            if (newDom > monthLen) 
                newDom = monthLen;

            // Set the DAY_OF_MONTH.  We rely on the fact that this field
            // takes precedence over everything else (since all other fields
            // are also set at this point).  If this fact changes (if the
            // disambiguation algorithm changes) then we will have to unset
            // the appropriate fields here so that DAY_OF_MONTH is attended
            // to.

            // If we are in the cutover month, manipulate ms directly.  Don't do
            // this in general because it doesn't work across DST boundaries
            // (details, details).  This takes care of the discontinuity.
            setTimeInMillis(cMonthStart + (newDom-1)*kOneDay, status);                
            return;
        }

    default:
        Calendar::roll(field, amount, status);
        return;
    }
}