diff --git a/source/i18n/smpdtfmt.cpp b/source/i18n/smpdtfmt.cpp index 29f7c436193..749c6ff984c 100644 --- a/source/i18n/smpdtfmt.cpp +++ b/source/i18n/smpdtfmt.cpp @@ -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 diff --git a/source/i18n/smpdtfmt.h b/source/i18n/smpdtfmt.h index bff71221842..588c09678a5 100644 --- a/source/i18n/smpdtfmt.h +++ b/source/i18n/smpdtfmt.h @@ -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. + * + *
+ * 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
+ * Unicode::isDigit()
, 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.
+ *
+ *
+ * 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. + * *
* For time zones that have no names, SimpleDateFormat uses strings GMT+hours:minutes or
* GMT-hours:minutes.
diff --git a/source/test/intltest/calregts.cpp b/source/test/intltest/calregts.cpp
index 4a976c100b8..c1a485e2379 100644
--- a/source/test/intltest/calregts.cpp
+++ b/source/test/intltest/calregts.cpp
@@ -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