ICU-28 DateFormat parses 2-digit years other than "00" through "99". Fix restricts parsing to those 2-digit year strings.

X-SVN-Rev: 64
This commit is contained in:
Alan Liu 1999-10-15 21:33:00 +00:00
parent b28e911c8c
commit 3ca6764857
4 changed files with 79 additions and 3 deletions

View file

@ -24,6 +24,8 @@
* Removed subParseLong
* Removed chk
* 02/22/99 stephen Removed character literals for EBCDIC safety
* 10/14/99 aliu Updated 2-digit year parsing so that only "00" thru
* "99" are recognized. {j28 4182066}
********************************************************************************
*/
@ -1117,12 +1119,15 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
case kEraField:
return matchString(text, start, Calendar::ERA, fSymbols->fEras, fSymbols->fErasCount);
case kYearField:
// If there are 4 or more YEAR pattern characters, this indicates
// If there are 3 or more YEAR pattern characters, this indicates
// that the year value is to be treated literally, without any
// two-digit year adjustments (e.g., from "01" to 2001). Otherwise
// we made adjustments to place the 2-digit year in the proper
// century -- unless the given year itself is more than two characters.
if (count <= 2 && (pos.getIndex() - start) <= 2)
// century, for parsed strings from "00" to "99". Any other string
// is treated literally: "2250", "-1", "1", "002".
if (count <= 2 && (pos.getIndex() - start) == 2
&& Unicode::isDigit(text.charAt(start))
&& Unicode::isDigit(text.charAt(start+1)))
{
// Assume for example that the defaultCenturyStart is 6/18/1903.
// This means that two-digit years will be forced into the range

View file

@ -23,6 +23,8 @@
* Removed subParseLong
* Removed getZoneIndex (added in DateFormatSymbols)
* 06/14/99 stephen Removed fgTimeZoneDataSuffix
* 10/14/99 aliu Updated class doc to describe 2-digit year parsing
* {j28 4182066}.
*******************************************************************************
*/
@ -135,6 +137,28 @@ class DateFormatSymbols;
* marker 'a' is left out from the format pattern while the "hour in am/pm"
* pattern symbol is used. This information loss can happen when formatting the
* time in PM.
*
* <p>
* When parsing a date string using the abbreviated year pattern ("y" or "yy"),
* SimpleDateFormat must interpret the abbreviated year
* relative to some century. It does this by adjusting dates to be
* within 80 years before and 20 years after the time the SimpleDateFormat
* instance is created. For example, using a pattern of "MM/dd/yy" and a
* SimpleDateFormat instance created on Jan 1, 1997, the string
* "01/11/12" would be interpreted as Jan 11, 2012 while the string "05/04/64"
* would be interpreted as May 4, 1964.
* During parsing, only strings consisting of exactly two digits, as defined by
* <code>Unicode::isDigit()</code>, will be parsed into the default century.
* Any other numeric string, such as a one digit string, a three or more digit
* string, or a two digit string that isn't all digits (for example, "-1"), is
* interpreted literally. So "01/02/3" or "01/02/003" are parsed, using the
* same pattern, as Jan 2, 3 AD. Likewise, "01/02/-3" is parsed as Jan 2, 4 BC.
*
* <p>
* If the year pattern has more than two 'y' characters, the year is
* interpreted literally, regardless of the number of digits. So using the
* pattern "MM/dd/yyyy", "01/11/12" parses to Jan 11, 12 A.D.
*
* <P>
* For time zones that have no names, SimpleDateFormat uses strings GMT+hours:minutes or
* GMT-hours:minutes.

View file

@ -70,6 +70,7 @@ CalendarRegressionTest::runIndexedTest( int32_t index, bool_t exec, char* &name,
CASE(32,Test4165343)
CASE(33,Test4166109)
CASE(34,Test4167060)
CASE(35,Test4197699)
default: name = ""; break;
}
@ -1580,8 +1581,53 @@ CalendarRegressionTest::Test4167060()
delete calendars[2];
}
/**
* Week of year is wrong at the start and end of the year.
*/
void CalendarRegressionTest::Test4197699() {
UErrorCode status = U_ZERO_ERROR;
GregorianCalendar cal(status);
cal.setFirstDayOfWeek(Calendar::MONDAY);
cal.setMinimalDaysInFirstWeek(4);
SimpleDateFormat fmt("E dd MMM yyyy 'DOY='D 'WOY='w",
Locale::US, status);
fmt.setCalendar(cal);
if (FAILURE(status)) {
errln("Couldn't initialize test");
return;
}
int32_t DATA[] = {
2000, Calendar::JANUARY, 1, 52,
2001, Calendar::DECEMBER, 31, 1,
};
int32_t DATA_length = sizeof(DATA) / sizeof(DATA[0]);
UnicodeString str;
DateFormat& dfmt = *(DateFormat*)&fmt;
for (int32_t i=0; i<DATA_length; ) {
cal.clear();
cal.set(DATA[i], DATA[i+1], DATA[i+2]);
i += 3;
int32_t expWOY = DATA[i++];
int32_t actWOY = cal.get(Calendar::WEEK_OF_YEAR, status);
if (expWOY == actWOY) {
logln(UnicodeString("Ok: ") + dfmt.format(cal.getTime(status), str.remove()));
} else {
errln(UnicodeString("FAIL: ") + dfmt.format(cal.getTime(status), str.remove())
+ ", expected WOY=" + expWOY);
cal.add(Calendar::DATE, -8, status);
for (int j=0; j<14; ++j) {
cal.add(Calendar::DATE, 1, status);
logln(dfmt.format(cal.getTime(status), str.remove()));
}
}
if (FAILURE(status)) {
errln("FAIL: Unexpected error from Calendar");
return;
}
}
}
UDate
CalendarRegressionTest::makeDate(int32_t y, int32_t m, int32_t d,

View file

@ -65,6 +65,7 @@ public:
void Test4165343(void) ;
void Test4166109(void) ;
void Test4167060(void) ;
void Test4197699();
void printdate(GregorianCalendar *cal, char *string);
void dowTest(bool_t lenient) ;