CalendarRegressionTest::Test4167060()
{
    UErrorCode status = U_ZERO_ERROR;
    UCalendarDateFields field = UCAL_YEAR;
    DateFormat *format = new SimpleDateFormat(UnicodeString("EEE MMM dd HH:mm:ss zzz yyyy G"),
        Locale::getUS(), status);
    if(U_FAILURE(status)) {
        dataerrln("Couldn't create SimpleDateFormat - %s", u_errorName(status));
        return;
    }

    GregorianCalendar *calendars [] = {
        new GregorianCalendar(100, UCAL_NOVEMBER, 1, status),
        new GregorianCalendar(-99 /*100BC*/, UCAL_JANUARY, 1, status),
        new GregorianCalendar(1996, UCAL_FEBRUARY, 29, status),
    };
    if(U_FAILURE(status)) {
        errln("Couldn't create GregorianCalendars");
        return;
        // could leak
    }

    UnicodeString id [] = { "Hybrid", "Gregorian", "Julian" };

    for (int32_t k=0; k<3; ++k) {
        logln("--- " + id[k] + " ---");

        for (int32_t j=0; j < 3; ++j) {
            GregorianCalendar *calendar = calendars[j];
            if (k == 1) {
                calendar->setGregorianChange(EARLIEST_SUPPORTED_MILLIS, status);
            }
            else if (k == 2) {
                calendar->setGregorianChange(LATEST_SUPPORTED_MILLIS, status);
            }

            if(U_FAILURE(status))
                errln("setGregorianChange() failed");
            format->adoptCalendar((Calendar*)calendar->clone());

            UDate dateBefore = calendar->getTime(status);
            if(U_FAILURE(status))
                errln("getTime() failed");

            int32_t maxYear = calendar->getActualMaximum(field, status);
            UnicodeString temp;
            logln(UnicodeString("maxYear: ") + maxYear + " for " + format->format(calendar->getTime(status), temp));
            temp.remove();
            logln("date before: " + format->format(dateBefore, temp));

            int32_t years[] = {2000, maxYear-1, maxYear, maxYear+1};

            for (int32_t i = 0; i < 4; i++) {
                UBool valid = years[i] <= maxYear;
                calendar->set(field, years[i]);
                UDate dateAfter = calendar->getTime(status);
                if(U_FAILURE(status))
                    errln("getTime() failed");
                int32_t newYear = calendar->get(field, status);
                if(U_FAILURE(status))
                    errln(UnicodeString("get(") + (int32_t)field + ") failed");
                calendar->setTime(dateBefore, status); // restore calendar for next use
                if(U_FAILURE(status))
                    errln("setTime() failed");

                temp.remove();
                logln(UnicodeString(" Year ") + years[i] + (valid? " ok " : " bad") +
                      " => " + format->format(dateAfter, temp));
                if (valid && newYear != years[i]) {
                    errln(UnicodeString("  FAIL: ") + newYear + " should be valid; date, month and time shouldn't change");
                }
                // {sfb} this next line is a hack, but it should work since if a
                // double has an exponent, adding 1 should not yield the same double
                else if (!valid && /*newYear == years[i]*/ dateAfter + 1.0 == dateAfter)  {
                    errln(UnicodeString("  FAIL: ") + newYear + " should be invalid");
                }
            }
        }
    }

    delete format;
    delete calendars[0];
    delete calendars[1];
    delete calendars[2];
}