]> granicus.if.org Git - icu/commitdiff
ICU-9226 Calendar add +year should always move forward in time; roll year should...
authorPeter Edberg <pedberg@unicode.org>
Tue, 19 Jun 2012 05:42:52 +0000 (05:42 +0000)
committerPeter Edberg <pedberg@unicode.org>
Tue, 19 Jun 2012 05:42:52 +0000 (05:42 +0000)
X-SVN-Rev: 31966

icu4c/source/i18n/calendar.cpp
icu4c/source/test/cintltst/ccaltst.c

index 225ca2a5b96c08eb70a28b61c10ffe1c478c0b58..41671de56589e970531cb573010b99b2ba3d2266 100644 (file)
@@ -1600,6 +1600,45 @@ void Calendar::roll(UCalendarDateFields field, int32_t amount, UErrorCode& statu
 
     case UCAL_YEAR:
     case UCAL_YEAR_WOY:
+        {
+            // * If era==0 and years go backwards in time, change sign of amount.
+            // * Until we have new API per #9393, we temporarily hardcode knowledge of
+            //   which calendars have era 0 years that go backwards.
+            UBool era0WithYearsThatGoBackwards = FALSE;
+            int32_t era = get(UCAL_ERA, status);
+            if (era == 0) {
+                const char * calType = getType();
+                if ( uprv_strcmp(calType,"gregorian")==0 || uprv_strcmp(calType,"roc")==0 || uprv_strcmp(calType,"coptic")==0 ) {
+                    amount = -amount;
+                    era0WithYearsThatGoBackwards = TRUE;
+                }
+            }
+            int32_t newYear = internalGet(field) + amount;
+            if (era > 0 || newYear >= 1) {
+                int32_t maxYear = getActualMaximum(field, status);
+                if (maxYear < 32768) {
+                    // this era has real bounds, roll should wrap years
+                    if (newYear < 1) {
+                        newYear = maxYear - ((-newYear) % maxYear);
+                    } else if (newYear > maxYear) {
+                        newYear = ((newYear - 1) % maxYear) + 1;
+                    }
+                // else era is unbounded, just pin low year instead of wrapping
+                } else if (newYear < 1) {
+                    newYear = 1;
+                }
+            // else we are in era 0 with newYear < 1;
+            // calendars with years that go backwards must pin the year value at 0,
+            // other calendars can have years < 0 in era 0
+            } else if (era0WithYearsThatGoBackwards) {
+                newYear = 1;
+            }
+            set(field, newYear);
+            pinField(UCAL_MONTH,status);
+            pinField(UCAL_DAY_OF_MONTH,status);
+            return;
+        }
+
     case UCAL_EXTENDED_YEAR:
         // Rolling the year can involve pinning the DAY_OF_MONTH.
         set(field, internalGet(field) + amount);
@@ -1861,8 +1900,25 @@ void Calendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status
         return;
 
     case UCAL_YEAR:
-    case UCAL_EXTENDED_YEAR:
     case UCAL_YEAR_WOY:
+      {
+        // * If era=0 and years go backwards in time, change sign of amount.
+        // * Until we have new API per #9393, we temporarily hardcode knowledge of
+        //   which calendars have era 0 years that go backwards.
+        // * Note that for UCAL_YEAR (but not UCAL_YEAR_WOY) we could instead handle
+        //   this by applying the amount to the UCAL_EXTENDED_YEAR field; but since
+        //   we would still need to handle UCAL_YEAR_WOY as below, might as well
+        //   also handle UCAL_YEAR the same way.
+        int32_t era = get(UCAL_ERA, status);
+        if (era == 0) {
+          const char * calType = getType();
+          if ( uprv_strcmp(calType,"gregorian")==0 || uprv_strcmp(calType,"roc")==0 || uprv_strcmp(calType,"coptic")==0 ) {
+            amount = -amount;
+          }
+        }
+      }
+      // Fall through into normal handling
+    case UCAL_EXTENDED_YEAR:
     case UCAL_MONTH:
       {
         UBool oldLenient = isLenient();
index 7f7f0aa833556c11966246a14bb4dccec7ee9620..66e1e1f0bbee8075ada96358a4cf5f93a39bb474 100644 (file)
@@ -32,6 +32,7 @@
 
 void TestGregorianChange(void);
 void TestFieldDifference(void);
+void TestAddRollEra0AndEraBounds(void);
 
 void addCalTest(TestNode** root);
 
@@ -50,6 +51,7 @@ void addCalTest(TestNode** root)
     addTest(root, &TestWeekend, "tsformat/ccaltst/TestWeekend");
     addTest(root, &TestFieldDifference, "tsformat/ccaltst/TestFieldDifference");
     addTest(root, &TestAmbiguousWallTime, "tsformat/ccaltst/TestAmbiguousWallTime");
+    addTest(root, &TestAddRollEra0AndEraBounds, "tsformat/ccaltst/TestAddRollEra0AndEraBounds");
 }
 
 /* "GMT" */
@@ -1655,46 +1657,46 @@ static void TestWeekend() {
         log_data_err("Unable to create UDateFormat - %s\n", u_errorName(fmtStatus));
         return;
     }
-       for (count = sizeof(testDates)/sizeof(testDates[0]); count-- > 0; ++testDatesPtr) {
+    for (count = sizeof(testDates)/sizeof(testDates[0]); count-- > 0; ++testDatesPtr) {
         UErrorCode status = U_ZERO_ERROR;
-               UCalendar * cal = ucal_open(NULL, 0, testDatesPtr->locale, UCAL_GREGORIAN, &status);
-               log_verbose("locale: %s\n", testDatesPtr->locale);
-               if (U_SUCCESS(status)) {
-                       const TestWeekendDates * weekendDatesPtr = testDatesPtr->dates;
-                       for (subCount = testDatesPtr->numDates; subCount--; ++weekendDatesPtr) {
-                               UDate dateToTest;
-                               UBool isWeekend;
-                               char  fmtDateBytes[kFormattedDateMax] = "<could not format test date>"; /* initialize for failure */
-
-                               ucal_clear(cal);
-                               ucal_setDateTime(cal, weekendDatesPtr->year, weekendDatesPtr->month, weekendDatesPtr->day,
-                                                                weekendDatesPtr->hour, 0, 0, &status);
-                               dateToTest = ucal_getMillis(cal, &status) + weekendDatesPtr->millisecOffset;
-                               isWeekend = ucal_isWeekend(cal, dateToTest, &status);
-                               if (U_SUCCESS(fmtStatus)) {
-                                   UChar fmtDate[kFormattedDateMax];
-                                   (void)udat_format(fmt, dateToTest, fmtDate, kFormattedDateMax, NULL, &fmtStatus);
-                                   if (U_SUCCESS(fmtStatus)) {
-                                               u_austrncpy(fmtDateBytes, fmtDate, kFormattedDateMax);
-                                               fmtDateBytes[kFormattedDateMax-1] = 0;
-                                   } else {
-                                       fmtStatus = U_ZERO_ERROR;
-                                   }
-                               }
-                               if ( U_FAILURE(status) ) {
-                                       log_err("FAIL: locale %s date %s isWeekend() status %s\n", testDatesPtr->locale, fmtDateBytes, u_errorName(status) );
-                                       status = U_ZERO_ERROR;
-                               } else if ( (isWeekend!=0) != (weekendDatesPtr->isWeekend!=0) ) {
-                                       log_err("FAIL: locale %s date %s isWeekend %d, expected the opposite\n", testDatesPtr->locale, fmtDateBytes, isWeekend );
-                               } else {
-                                       log_verbose("OK:   locale %s date %s isWeekend %d\n", testDatesPtr->locale, fmtDateBytes, isWeekend );
-                               }
-                       }
-                       ucal_close(cal);
-               } else {
-                       log_data_err("FAIL: ucal_open for locale %s failed: %s - (Are you missing data?)\n", testDatesPtr->locale, u_errorName(status) );
-               }
-       }
+        UCalendar * cal = ucal_open(NULL, 0, testDatesPtr->locale, UCAL_GREGORIAN, &status);
+        log_verbose("locale: %s\n", testDatesPtr->locale);
+        if (U_SUCCESS(status)) {
+            const TestWeekendDates * weekendDatesPtr = testDatesPtr->dates;
+            for (subCount = testDatesPtr->numDates; subCount--; ++weekendDatesPtr) {
+                UDate dateToTest;
+                UBool isWeekend;
+                char  fmtDateBytes[kFormattedDateMax] = "<could not format test date>"; /* initialize for failure */
+
+                ucal_clear(cal);
+                ucal_setDateTime(cal, weekendDatesPtr->year, weekendDatesPtr->month, weekendDatesPtr->day,
+                                 weekendDatesPtr->hour, 0, 0, &status);
+                dateToTest = ucal_getMillis(cal, &status) + weekendDatesPtr->millisecOffset;
+                isWeekend = ucal_isWeekend(cal, dateToTest, &status);
+                if (U_SUCCESS(fmtStatus)) {
+                    UChar fmtDate[kFormattedDateMax];
+                    (void)udat_format(fmt, dateToTest, fmtDate, kFormattedDateMax, NULL, &fmtStatus);
+                    if (U_SUCCESS(fmtStatus)) {
+                        u_austrncpy(fmtDateBytes, fmtDate, kFormattedDateMax);
+                        fmtDateBytes[kFormattedDateMax-1] = 0;
+                    } else {
+                        fmtStatus = U_ZERO_ERROR;
+                    }
+                }
+                if ( U_FAILURE(status) ) {
+                    log_err("FAIL: locale %s date %s isWeekend() status %s\n", testDatesPtr->locale, fmtDateBytes, u_errorName(status) );
+                    status = U_ZERO_ERROR;
+                } else if ( (isWeekend!=0) != (weekendDatesPtr->isWeekend!=0) ) {
+                    log_err("FAIL: locale %s date %s isWeekend %d, expected the opposite\n", testDatesPtr->locale, fmtDateBytes, isWeekend );
+                } else {
+                    log_verbose("OK:   locale %s date %s isWeekend %d\n", testDatesPtr->locale, fmtDateBytes, isWeekend );
+                }
+            }
+            ucal_close(cal);
+        } else {
+            log_data_err("FAIL: ucal_open for locale %s failed: %s - (Are you missing data?)\n", testDatesPtr->locale, u_errorName(status) );
+        }
+    }
     if (U_SUCCESS(fmtStatus)) {
         udat_close(fmt);
     }
@@ -1712,12 +1714,12 @@ static void TestWeekend() {
                     transition = ucal_getWeekendTransition(cal, daysOfWeekPtr->dayOfWeek, &status); 
                 }
                 if ( U_FAILURE(status) ) {
-                                       log_err("FAIL: locale %s DOW %d getDayOfWeekType() status %s\n", testDaysPtr->locale, daysOfWeekPtr->dayOfWeek, u_errorName(status) );
-                                       status = U_ZERO_ERROR;
+                    log_err("FAIL: locale %s DOW %d getDayOfWeekType() status %s\n", testDaysPtr->locale, daysOfWeekPtr->dayOfWeek, u_errorName(status) );
+                    status = U_ZERO_ERROR;
                 } else if ( dayType != daysOfWeekPtr->dayType || transition != daysOfWeekPtr->transition ) {
-                                       log_err("FAIL: locale %s DOW %d type %d, expected %d\n", testDaysPtr->locale, daysOfWeekPtr->dayOfWeek, dayType, daysOfWeekPtr->dayType );
+                    log_err("FAIL: locale %s DOW %d type %d, expected %d\n", testDaysPtr->locale, daysOfWeekPtr->dayOfWeek, dayType, daysOfWeekPtr->dayType );
                 } else {
-                                       log_verbose("OK:   locale %s DOW %d type %d\n", testDaysPtr->locale, daysOfWeekPtr->dayOfWeek, dayType );
+                    log_verbose("OK:   locale %s DOW %d type %d\n", testDaysPtr->locale, daysOfWeekPtr->dayOfWeek, dayType );
                 }
             }
             ucal_close(cal);
@@ -1937,4 +1939,221 @@ void TestAmbiguousWallTime() {
     ucal_close(ucal);
 }
 
+/**
+ * TestAddRollEra0AndEraBounds, for #9226
+ */
+ typedef struct {
+     const char * locale;
+     UBool era0YearsGoBackwards; /* until we have API to get this, per #9393 */
+ } EraTestItem;
+
+static const EraTestItem eraTestItems[] = {
+    /* calendars with non-modern era 0 that goes backwards, max era == 1 */
+    { "en@calendar=gregorian", TRUE },
+    { "en@calendar=roc", TRUE },
+    { "en@calendar=coptic", TRUE },
+    /* calendars with non-modern era 0 that goes forwards, max era > 1 */
+    { "en@calendar=japanese", FALSE },
+    { "en@calendar=chinese", FALSE },
+    /* calendars with non-modern era 0 that goes forwards, max era == 1 */
+    { "en@calendar=ethiopic", FALSE },
+    /* calendars with only one era  = 0, forwards */
+    { "en@calendar=buddhist", FALSE },
+    { "en@calendar=hebrew", FALSE },
+    { "en@calendar=islamic", FALSE },
+    { "en@calendar=indian", FALSE },
+    { "en@calendar=persian", FALSE },
+    { "en@calendar=ethiopic-amete-alem", FALSE },
+    { NULL, FALSE }
+};
+
+static const UChar zoneGMT[] = { 0x47,0x4D,0x54,0 };
+
+void TestAddRollEra0AndEraBounds() {
+    const EraTestItem * eraTestItemPtr;
+    for (eraTestItemPtr = eraTestItems; eraTestItemPtr->locale != NULL; eraTestItemPtr++) {
+        UErrorCode status = U_ZERO_ERROR;
+        UCalendar *ucalTest = ucal_open(zoneGMT, -1, eraTestItemPtr->locale, UCAL_DEFAULT, &status);
+        if ( U_SUCCESS(status) ) {
+            int32_t yrBefore, yrAfter, yrMax, eraAfter, eraMax, eraNow;
+
+            status = U_ZERO_ERROR;
+            ucal_clear(ucalTest);
+            ucal_set(ucalTest, UCAL_YEAR, 2);
+            ucal_set(ucalTest, UCAL_ERA, 0);
+            yrBefore = ucal_get(ucalTest, UCAL_YEAR, &status);
+            ucal_add(ucalTest, UCAL_YEAR, 1, &status);
+            yrAfter = ucal_get(ucalTest, UCAL_YEAR, &status);
+            if (U_FAILURE(status)) {
+                log_err("FAIL: set era 0 year 2 then add 1 year and get year for %s, error %s\n",
+                        eraTestItemPtr->locale, u_errorName(status));
+            } else if ( (eraTestItemPtr->era0YearsGoBackwards && yrAfter>yrBefore) ||
+                        (!eraTestItemPtr->era0YearsGoBackwards && yrAfter<yrBefore) ) {
+                log_err("FAIL: era 0 add 1 year does not move forward in time for %s\n", eraTestItemPtr->locale);
+            }
+            
+            status = U_ZERO_ERROR;
+            ucal_clear(ucalTest);
+            ucal_set(ucalTest, UCAL_YEAR, 2);
+            ucal_set(ucalTest, UCAL_ERA, 0);
+            yrBefore = ucal_get(ucalTest, UCAL_YEAR, &status);
+            ucal_roll(ucalTest, UCAL_YEAR, 1, &status);
+            yrAfter = ucal_get(ucalTest, UCAL_YEAR, &status);
+            if (U_FAILURE(status)) {
+                log_err("FAIL: set era 0 year 2 then roll 1 year and get year for %s, error %s\n",
+                        eraTestItemPtr->locale, u_errorName(status));
+            } else if ( (eraTestItemPtr->era0YearsGoBackwards && yrAfter>yrBefore) ||
+                        (!eraTestItemPtr->era0YearsGoBackwards && yrAfter<yrBefore) ) {
+                log_err("FAIL: era 0 roll 1 year does not move forward in time for %s\n", eraTestItemPtr->locale);
+            }
+            
+            status = U_ZERO_ERROR;
+            ucal_clear(ucalTest);
+            ucal_set(ucalTest, UCAL_YEAR, 1);
+            ucal_set(ucalTest, UCAL_ERA, 0);
+            if (eraTestItemPtr->era0YearsGoBackwards) {
+                ucal_roll(ucalTest, UCAL_YEAR, 1, &status); /* roll forward in time to era 0 boundary */
+                yrAfter = ucal_get(ucalTest, UCAL_YEAR, &status);
+                eraAfter = ucal_get(ucalTest, UCAL_ERA, &status);
+                if (U_FAILURE(status)) {
+                    log_err("FAIL: set era 0 year 1 then roll 1 year and get year,era for %s, error %s\n",
+                            eraTestItemPtr->locale, u_errorName(status));
+                /* all calendars with era0YearsGoBackwards have "unbounded" era0 year values, so we should pin at yr 1 */
+                } else if (eraAfter != 0 || yrAfter != 1) {
+                    log_err("FAIL: era 0 roll 1 year from year 1 does not stay within era or pin to year 1 for %s (get era %d year %d)\n",
+                            eraTestItemPtr->locale, eraAfter, yrAfter);
+                }
+            } else {
+                /* roll backward in time to where era 0 years go negative, except for the Chinese
+                   calendar, which uses negative eras instead of having years outside the range 1-60 */
+                const char * calType = ucal_getType(ucalTest, &status);
+                ucal_roll(ucalTest, UCAL_YEAR, -2, &status);
+                yrAfter = ucal_get(ucalTest, UCAL_YEAR, &status);
+                eraAfter = ucal_get(ucalTest, UCAL_ERA, &status);
+                if (U_FAILURE(status)) {
+                    log_err("FAIL: set era 0 year 1 then roll -2 years and get year,era for %s, error %s\n",
+                            eraTestItemPtr->locale, u_errorName(status));
+                } else if ( uprv_strcmp(calType,"chinese")!=0 && (eraAfter != 0 || yrAfter != -1) ) {
+                    log_err("FAIL: era 0 roll -2 years from year 1 does not stay within era or produce year -1 for %s (get era %d year %d)\n",
+                            eraTestItemPtr->locale, eraAfter, yrAfter);
+                }
+            }
+            
+            status = U_ZERO_ERROR;
+            ucal_clear(ucalTest);
+            ucal_set(ucalTest, UCAL_YEAR, 1);
+            ucal_set(ucalTest, UCAL_ERA, 0);
+            eraMax = ucal_getLimit(ucalTest, UCAL_ERA, UCAL_MAXIMUM, &status);
+            if ( U_SUCCESS(status) && eraMax > 0 ) {
+                /* try similar tests for era 1 (if calendar has it), in which years always go forward */
+                status = U_ZERO_ERROR;
+                ucal_clear(ucalTest);
+                ucal_set(ucalTest, UCAL_YEAR, 2);
+                ucal_set(ucalTest, UCAL_ERA, 1);
+                yrBefore = ucal_get(ucalTest, UCAL_YEAR, &status);
+                ucal_add(ucalTest, UCAL_YEAR, 1, &status);
+                yrAfter = ucal_get(ucalTest, UCAL_YEAR, &status);
+                if (U_FAILURE(status)) {
+                    log_err("FAIL: set era 1 year 2 then add 1 year and get year for %s, error %s\n",
+                            eraTestItemPtr->locale, u_errorName(status));
+                } else if ( yrAfter<yrBefore ) {
+                    log_err("FAIL: era 1 add 1 year does not move forward in time for %s\n", eraTestItemPtr->locale);
+                }
+                
+                status = U_ZERO_ERROR;
+                ucal_clear(ucalTest);
+                ucal_set(ucalTest, UCAL_YEAR, 2);
+                ucal_set(ucalTest, UCAL_ERA, 1);
+                yrBefore = ucal_get(ucalTest, UCAL_YEAR, &status);
+                ucal_roll(ucalTest, UCAL_YEAR, 1, &status);
+                yrAfter = ucal_get(ucalTest, UCAL_YEAR, &status);
+                if (U_FAILURE(status)) {
+                    log_err("FAIL: set era 1 year 2 then roll 1 year and get year for %s, error %s\n",
+                            eraTestItemPtr->locale, u_errorName(status));
+                } else if ( yrAfter<yrBefore ) {
+                    log_err("FAIL: era 1 roll 1 year does not move forward in time for %s\n", eraTestItemPtr->locale);
+                }
+                
+                status = U_ZERO_ERROR;
+                ucal_clear(ucalTest);
+                ucal_set(ucalTest, UCAL_YEAR, 1);
+                ucal_set(ucalTest, UCAL_ERA, 1);
+                yrMax = ucal_getLimit(ucalTest, UCAL_YEAR, UCAL_ACTUAL_MAXIMUM, &status); /* max year value for era 1 */
+                ucal_roll(ucalTest, UCAL_YEAR, -1, &status); /* roll down which should pin or wrap to end */
+                yrAfter = ucal_get(ucalTest, UCAL_YEAR, &status);
+                eraAfter = ucal_get(ucalTest, UCAL_ERA, &status);
+                if (U_FAILURE(status)) {
+                    log_err("FAIL: set era 1 year 1 then roll -1 year and get year,era for %s, error %s\n",
+                            eraTestItemPtr->locale, u_errorName(status));
+                /* if yrMax is reasonable we should wrap to that, else we should pin at yr 1 */
+                } else if (yrMax >= 32768) {
+                    if (eraAfter != 1 || yrAfter != 1) {
+                        log_err("FAIL: era 1 roll -1 year from year 1 does not stay within era or pin to year 1 for %s (get era %d year %d)\n",
+                                eraTestItemPtr->locale, eraAfter, yrAfter);
+                    }
+                } else if (eraAfter != 1 || yrAfter != yrMax) {
+                    log_err("FAIL: era 1 roll -1 year from year 1 does not stay within era or wrap to year %d for %s (get era %d year %d)\n",
+                            yrMax, eraTestItemPtr->locale, eraAfter, yrAfter);
+                } else {
+                    /* now roll up which should wrap to beginning */
+                    ucal_roll(ucalTest, UCAL_YEAR, 1, &status); /* now roll up which should wrap to beginning */
+                    yrAfter = ucal_get(ucalTest, UCAL_YEAR, &status);
+                    eraAfter = ucal_get(ucalTest, UCAL_ERA, &status);
+                    if (U_FAILURE(status)) {
+                        log_err("FAIL: era 1 roll 1 year from end and get year,era for %s, error %s\n",
+                                eraTestItemPtr->locale, u_errorName(status));
+                    } else if (eraAfter != 1 || yrAfter != 1) {
+                        log_err("FAIL: era 1 roll 1 year from year %d does not stay within era or wrap to year 1 for %s (get era %d year %d)\n",
+                                yrMax, eraTestItemPtr->locale, eraAfter, yrAfter);
+                    }
+                }
+
+                /* if current era  > 1, try the same roll tests for current era */
+                ucal_setMillis(ucalTest, ucal_getNow(), &status);
+                eraNow = ucal_get(ucalTest, UCAL_ERA, &status);
+                if ( U_SUCCESS(status) && eraNow > 1 ) {
+                    status = U_ZERO_ERROR;
+                    ucal_clear(ucalTest);
+                    ucal_set(ucalTest, UCAL_YEAR, 1);
+                    ucal_set(ucalTest, UCAL_ERA, eraNow);
+                    yrMax = ucal_getLimit(ucalTest, UCAL_YEAR, UCAL_ACTUAL_MAXIMUM, &status); /* max year value for this era */
+                    ucal_roll(ucalTest, UCAL_YEAR, -1, &status);
+                    yrAfter = ucal_get(ucalTest, UCAL_YEAR, &status);
+                    eraAfter = ucal_get(ucalTest, UCAL_ERA, &status);
+                    if (U_FAILURE(status)) {
+                        log_err("FAIL: set era %d year 1 then roll -1 year and get year,era for %s, error %s\n",
+                                eraNow, eraTestItemPtr->locale, u_errorName(status));
+                    /* if yrMax is reasonable we should wrap to that, else we should pin at yr 1 */
+                    } else if (yrMax >= 32768) {
+                        if (eraAfter != eraNow || yrAfter != 1) {
+                            log_err("FAIL: era %d roll -1 year from year 1 does not stay within era or pin to year 1 for %s (get era %d year %d)\n",
+                                    eraNow, eraTestItemPtr->locale, eraAfter, yrAfter);
+                        }
+                    } else if (eraAfter != eraNow || yrAfter != yrMax) {
+                        log_err("FAIL: era %d roll -1 year from year 1 does not stay within era or wrap to year %d for %s (get era %d year %d)\n",
+                                eraNow, yrMax, eraTestItemPtr->locale, eraAfter, yrAfter);
+                    } else {
+                        /* now roll up which should wrap to beginning */
+                        ucal_roll(ucalTest, UCAL_YEAR, 1, &status); /* now roll up which should wrap to beginning */
+                        yrAfter = ucal_get(ucalTest, UCAL_YEAR, &status);
+                        eraAfter = ucal_get(ucalTest, UCAL_ERA, &status);
+                        if (U_FAILURE(status)) {
+                            log_err("FAIL: era %d roll 1 year from end and get year,era for %s, error %s\n",
+                                    eraNow, eraTestItemPtr->locale, u_errorName(status));
+                        } else if (eraAfter != eraNow || yrAfter != 1) {
+                            log_err("FAIL: era %d roll 1 year from year %d does not stay within era or wrap to year 1 for %s (get era %d year %d)\n",
+                                    eraNow, yrMax, eraTestItemPtr->locale, eraAfter, yrAfter);
+                        }
+                    }
+                }
+            }
+
+            ucal_close(ucalTest);
+        } else {
+            log_data_err("FAIL: ucal_open fails for zone GMT, locale %s, UCAL_DEFAULT\n", eraTestItemPtr->locale);
+        }
+    }
+}
+
 #endif /* #if !UCONFIG_NO_FORMATTING */