- // 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;
+ // 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;