ICU-6745 ceToJD needs to handle months out of range 0-12 (e.g. from add, set)

X-SVN-Rev: 25458
This commit is contained in:
Peter Edberg 2009-02-21 03:59:16 +00:00
parent 5d17555c7e
commit 5927c7bedb
3 changed files with 92 additions and 8 deletions

View file

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 2003 - 2008, International Business Machines Corporation and *
* Copyright (C) 2003 - 2009, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
@ -109,13 +109,21 @@ CECalendar::haveDefaultCentury() const
int32_t
CECalendar::ceToJD(int32_t year, int32_t month, int32_t date, int32_t jdEpochOffset)
{
// handle month > 12, < 0 (e.g. from add/set)
if ( month >= 0 ) {
year += month/13;
month %= 13;
} else {
++month;
year += month/13 - 1;
month = month%13 + 12;
}
return (int32_t) (
(jdEpochOffset+365) // difference from Julian epoch to 1,1,1
+ 365 * (year - 1) // number of days from years
jdEpochOffset // difference from Julian epoch to 1,1,1
+ 365 * year // number of days from years
+ ClockMath::floorDivide(year, 4) // extra day of leap year
+ 30 * (month + 1) // number of days from months
+ date // number of days for present month
- 31 // slack?
+ 30 * month // number of days from months (months are 0-based)
+ date - 1 // number of days for present month (1 based)
);
}

View file

@ -1,6 +1,6 @@
/********************************************************************
* COPYRIGHT:
* Copyright (c) 1997-2008, International Business Machines Corporation
* Copyright (c) 1997-2009, International Business Machines Corporation
* and others. All Rights Reserved.
********************************************************************/
@ -82,6 +82,7 @@ CalendarRegressionTest::runIndexedTest( int32_t index, UBool exec, const char* &
CASE(43,TestTimeZoneTransitionAdd);
CASE(44,TestDeprecates);
CASE(45,TestT5555);
CASE(46,TestT6745);
default: name = ""; break;
}
}
@ -2309,6 +2310,80 @@ void CalendarRegressionTest::TestT5555()
delete cal;
}
typedef struct {
int32_t startYear;
int32_t startMonth; // 0-based
int32_t startDay; // 1-based
UCalendarDateFields fieldToChange;
int32_t fieldDelta;
int32_t endYear;
int32_t endMonth; // 0-based
int32_t endDay; // 1-based
} CoptEthCalTestItem;
// year 1724 in coptic calendar =
// year 2000 in ethiopic calendar (276 more than coptic) =
// year 7500 in ethiopic-amete-alem calendar (5776 more than coptic)
// (2007-2008 in gregorian calendar depending on month)
static const CoptEthCalTestItem coptEthCalTestItems[] = {
{ 1724, 12, 1, UCAL_MONTH, +1, 1725, 0, 1 },
{ 1724, 12, 1, UCAL_MONTH, +9, 1725, 8, 1 },
{ 1723, 12, 2, UCAL_MONTH, +1, 1724, 0, 2 }, // 1723 is a leap year
{ 1723, 12, 2, UCAL_MONTH, +9, 1724, 8, 2 },
{ 1725, 0, 1, UCAL_MONTH, -1, 1724, 12, 1 },
{ 1725, 0, 1, UCAL_MONTH, -6, 1724, 7, 1 },
{ 1724, 12, 1, UCAL_DATE, +8, 1725, 0, 4 },
{ 1723, 12, 1, UCAL_DATE, +8, 1724, 0, 3 }, // 1723 is a leap year
{ 1724, 0, 1, UCAL_DATE, -1, 1723, 12, 6 }, // 1723 is a leap year
{ 0, 0, 0, (UCalendarDateFields)0, 0, 0, 0, 0 } // terminator
};
typedef struct {
const char * locale;
int32_t yearOffset;
} CoptEthCalLocale;
static const CoptEthCalLocale copEthCalLocales[] = {
{ "en@calendar=coptic", 0 },
{ "en@calendar=ethiopic", 276 },
{ NULL, 0 } // terminator
};
void CalendarRegressionTest::TestT6745()
{
const CoptEthCalLocale * testLocalePtr;
for ( testLocalePtr = copEthCalLocales; testLocalePtr->locale != NULL; ++testLocalePtr) {
UErrorCode status = U_ZERO_ERROR;
Calendar *cal = Calendar::createInstance(Locale(testLocalePtr->locale), status);
if ( U_FAILURE(status) ) {
errln((UnicodeString)"FAIL: Calendar::createInstance, locale " + testLocalePtr->locale + ", status " + u_errorName(status));
continue;
}
const CoptEthCalTestItem * testItemPtr;
for (testItemPtr = coptEthCalTestItems; testItemPtr->fieldDelta != 0; ++testItemPtr) {
status = U_ZERO_ERROR;
cal->set( testItemPtr->startYear + testLocalePtr->yearOffset, testItemPtr->startMonth, testItemPtr->startDay, 9, 0 );
cal->add( testItemPtr->fieldToChange, testItemPtr->fieldDelta, status );
if ( U_FAILURE(status) ) {
errln((UnicodeString)"FAIL: Calendar::add, locale " + testLocalePtr->locale + ", field/delta " +
testItemPtr->fieldToChange + "/" + testItemPtr->fieldDelta + ", status " + u_errorName(status));
continue;
}
int32_t endYear = testItemPtr->endYear + testLocalePtr->yearOffset;
int32_t year = cal->get(UCAL_YEAR, status);
int32_t month = cal->get(UCAL_MONTH, status);
int32_t day = cal->get(UCAL_DATE, status);
if ( U_FAILURE(status) || year != endYear || month != testItemPtr->endMonth || day != testItemPtr->endDay ) {
errln((UnicodeString)"ERROR: Calendar::add, locale " + testLocalePtr->locale + ", field/delta " +
testItemPtr->fieldToChange + "/" + testItemPtr->fieldDelta + ", status " + u_errorName(status) +
", expected " + endYear + "/" + testItemPtr->endMonth + "/" + testItemPtr->endDay +
", got " + year + "/" + month + "/" + day );
}
}
delete cal;
}
}
/**
* Test behavior of fieldDifference around leap years. Also test a large
* field difference to check binary search.

View file

@ -1,6 +1,6 @@
/********************************************************************
* COPYRIGHT:
* Copyright (c) 1997-2007, International Business Machines Corporation and
* Copyright (c) 1997-2009, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************/
@ -65,6 +65,7 @@ public:
void TestJ81(void);
void TestJ438(void);
void TestT5555(void);
void TestT6745(void);
void TestLeapFieldDifference(void);
void TestMalaysianInstance(void);
void TestWeekShift(void);