ICU-32 DateFormat does not parse Feb 29 2000. This is a bug in GregorianCalendar era handling. Fixed algorithm, added test.

X-SVN-Rev: 70
This commit is contained in:
Alan Liu 1999-10-16 01:35:16 +00:00
parent 14aa1a76bc
commit 579961ed20
4 changed files with 74 additions and 3 deletions

View file

@ -34,6 +34,8 @@
* 09/14/98 stephen Changed type of kOneDay, kOneWeek to double.
* Fixed bug in roll()
* 10/15/99 aliu Fixed j31, incorrect WEEK_OF_YEAR computation.
* 10/15/99 aliu Fixed j32, cannot set date to Feb 29 2000 AD.
* {JDK bug 4210209 4209272}
********************************************************************************
*/
@ -540,7 +542,7 @@ int32_t
GregorianCalendar::monthLength(int32_t month) const
{
int32_t year = internalGet(YEAR);
if(internalGet(ERA) == BC) {
if(internalGetEra() == BC) {
year = 1 - year;
}
@ -614,7 +616,7 @@ GregorianCalendar::computeFields(UErrorCode& status)
// Time to fields takes the wall millis (Standard or DST).
timeToFields(localMillis, FALSE, status);
uint8_t era = (uint8_t) internalGet(ERA);
uint8_t era = (uint8_t) internalGetEra();
int32_t year = internalGet(YEAR);
int32_t month = internalGet(MONTH);
int32_t date = internalGet(DATE);
@ -1198,7 +1200,7 @@ GregorianCalendar::add(EDateFields field, int32_t amount, UErrorCode& status)
if (field == YEAR) {
int32_t year = internalGet(YEAR);
if (internalGet(ERA) == AD) {
if (internalGetEra() == AD) {
year += amount;
if (year > 0)
set(YEAR, year);
@ -1795,4 +1797,13 @@ GregorianCalendar::getISOYear(UErrorCode& status)
return isoYear;
}
/**
* 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(ERA) ? internalGet(ERA) : AD;
}
//eof

View file

@ -23,6 +23,8 @@
* Fixed bug in roll()
* 10/15/99 aliu Fixed j31, incorrect WEEK_OF_YEAR computation.
* Added documentation of WEEK_OF_YEAR computation.
* 10/15/99 aliu Fixed j32, cannot set date to Feb 29 2000 AD.
* {JDK bug 4210209 4209272}
********************************************************************************
*/
@ -460,6 +462,12 @@ private:
*/
int32_t getISOYear(UErrorCode& status);
/**
* 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 internalGetEra() const;
// this is 2^52 - 1, the largest allowable mantissa with a 0 exponent in a 64-bit double
static const UDate EARLIEST_SUPPORTED_MILLIS;
static const UDate LATEST_SUPPORTED_MILLIS;

View file

@ -54,6 +54,7 @@ DateFormatRegressionTest::runIndexedTest( int32_t index, bool_t exec, char* &nam
CASE(20,Test4151706)
CASE(21,Test4162071)
CASE(22,Test4182066)
CASE(23,Test4210209)
default: name = ""; break;
}
@ -1086,5 +1087,55 @@ void DateFormatRegressionTest::Test4182066() {
}
}
/**
* j32 {JDK Bug 4210209 4209272}
* DateFormat cannot parse Feb 29 2000 when setLenient(false)
*/
void
DateFormatRegressionTest::Test4210209() {
UErrorCode status = U_ZERO_ERROR;
UnicodeString pattern("MMM d, yyyy");
SimpleDateFormat sfmt(pattern, Locale::US, status);
SimpleDateFormat sdisp("MMM dd yyyy GG", Locale::US, status);
DateFormat& fmt = *(DateFormat*)&sfmt; // Yuck: See j25
DateFormat& disp = *(DateFormat*)&sdisp; // Yuck: See j25
if (FAILURE(status)) {
errln("Couldn't create SimpleDateFormat");
return;
}
Calendar* calx = (Calendar*)fmt.getCalendar(); // cast away const!
calx->setLenient(FALSE);
UDate d = date(2000-1900, Calendar::FEBRUARY, 29);
UnicodeString s, ss;
fmt.format(d, s);
logln(disp.format(d, ss.remove()) + " f> " + pattern +
" => \"" + s + "\"");
ParsePosition pos(0);
d = fmt.parse(s, pos);
logln(UnicodeString("\"") + s + "\" p> " + pattern +
" => " + disp.format(d, ss.remove()));
logln(UnicodeString("Parse pos = ") + pos.getIndex() +
", error pos = " + pos.getErrorIndex());
if (pos.getErrorIndex() != -1) {
errln(UnicodeString("FAIL: Error index should be -1"));
}
// The underlying bug is in GregorianCalendar. If the following lines
// succeed, the bug is fixed. If the bug isn't fixed, they will throw
// an exception.
GregorianCalendar cal(status);
if (FAILURE(status)) {
errln("FAIL: Unable to create Calendar");
return;
}
cal.clear();
cal.setLenient(FALSE);
cal.set(2000, Calendar::FEBRUARY, 29); // This should work!
logln(UnicodeString("Attempt to set Calendar to Feb 29 2000: ") +
disp.format(cal.getTime(status), ss.remove()));
if (FAILURE(status)) {
errln("FAIL: Unable to set Calendar to Feb 29 2000");
}
}
//eof

View file

@ -51,6 +51,7 @@ public:
void Test4151706(void);
void Test4162071(void);
void Test4182066();
void Test4210209();
};
#endif // _DATEFORMATREGRESSIONTEST_