mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-06 22:15:31 +00:00
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:
parent
14aa1a76bc
commit
579961ed20
4 changed files with 74 additions and 3 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -51,6 +51,7 @@ public:
|
|||
void Test4151706(void);
|
||||
void Test4162071(void);
|
||||
void Test4182066();
|
||||
void Test4210209();
|
||||
};
|
||||
|
||||
#endif // _DATEFORMATREGRESSIONTEST_
|
||||
|
|
Loading…
Add table
Reference in a new issue