ICU-6420 Fixed calendar/date symbols mismatch problem for C.

X-SVN-Rev: 25309
This commit is contained in:
Yoshito Umaoka 2009-01-23 23:15:42 +00:00
parent c6efa90f2d
commit f682a39582
4 changed files with 206 additions and 28 deletions

View File

@ -1,6 +1,6 @@
/*
*******************************************************************************
* Copyright (C) 1997-2008, International Business Machines Corporation and *
* Copyright (C) 1997-2009, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
@ -514,6 +514,19 @@ SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo, FieldPosition&
pos.setBeginIndex(0);
pos.setEndIndex(0);
Calendar *workCal = &cal;
TimeZone *backupTZ = NULL;
if (&cal != fCalendar && uprv_strcmp(cal.getType(), fCalendar->getType()) != 0) {
// Different calendar type
// We use the time and time zone from the input calendar, but
// do not use the input calendar for field calculation.
UDate t = cal.getTime(status);
fCalendar->setTime(t, status);
backupTZ = fCalendar->getTimeZone().clone();
fCalendar->setTimeZone(cal.getTimeZone());
workCal = fCalendar;
}
UBool inQuote = FALSE;
UChar prevCh = 0;
int32_t count = 0;
@ -525,7 +538,7 @@ SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo, FieldPosition&
// Use subFormat() to format a repeated pattern character
// when a different pattern or non-pattern character is seen
if (ch != prevCh && count > 0) {
subFormat(appendTo, prevCh, count, pos, cal, status);
subFormat(appendTo, prevCh, count, pos, *workCal, status);
count = 0;
}
if (ch == QUOTE) {
@ -553,7 +566,12 @@ SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo, FieldPosition&
// Format the last item in the pattern, if any
if (count > 0) {
subFormat(appendTo, prevCh, count, pos, cal, status);
subFormat(appendTo, prevCh, count, pos, *workCal, status);
}
if (backupTZ != NULL) {
// Restore the original time zone
fCalendar->adoptTimeZone(backupTZ);
}
// and if something failed (e.g., an invalid format character), reset our FieldPosition
@ -1337,8 +1355,10 @@ UBool SimpleDateFormat::isNumeric(UChar formatChar, int32_t count) {
void
SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition& parsePos) const
{
UErrorCode status = U_ZERO_ERROR;
int32_t pos = parsePos.getIndex();
int32_t start = pos;
UBool ambiguousYear[] = { FALSE };
int32_t count = 0;
@ -1357,6 +1377,21 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
const UnicodeString numericFormatChars(NUMERIC_FORMAT_CHARS);
TimeZone *backupTZ = NULL;
Calendar *workCal = &cal;
if (&cal != fCalendar && uprv_strcmp(cal.getType(), fCalendar->getType()) != 0) {
// Different calendar type
// We use the time/zone from the input calendar, but
// do not use the input calendar for field calculation.
fCalendar->setTime(cal.getTime(status),status);
if (U_FAILURE(status)) {
goto ExitParse;
}
backupTZ = fCalendar->getTimeZone().clone();
fCalendar->setTimeZone(cal.getTimeZone());
workCal = fCalendar;
}
for (int32_t i=0; i<fPattern.length(); ++i) {
UChar ch = fPattern.charAt(i);
@ -1422,14 +1457,13 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
if (fieldPat == abutPat) {
count -= abutPass++;
if (count == 0) {
parsePos.setIndex(start);
parsePos.setErrorIndex(pos);
return;
status = U_PARSE_ERROR;
goto ExitParse;
}
}
pos = subParse(text, pos, ch, count,
TRUE, FALSE, ambiguousYear, cal);
TRUE, FALSE, ambiguousYear, *workCal);
// If the parse fails anywhere in the run, back up to the
// start of the run and retry.
@ -1443,15 +1477,14 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
// Handle non-numeric fields and non-abutting numeric
// fields.
else {
int32_t s = pos;
pos = subParse(text, pos, ch, count,
FALSE, TRUE, ambiguousYear, cal);
int32_t s = subParse(text, pos, ch, count,
FALSE, TRUE, ambiguousYear, *workCal);
if (pos < 0) {
parsePos.setErrorIndex(s);
parsePos.setIndex(start);
return;
if (s < 0) {
status = U_PARSE_ERROR;
goto ExitParse;
}
pos = s;
}
}
@ -1504,9 +1537,8 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
}
// We fall through to this point if the match fails
parsePos.setIndex(start);
parsePos.setErrorIndex(pos);
return;
status = U_PARSE_ERROR;
goto ExitParse;
}
}
@ -1538,7 +1570,6 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
// when the two-digit year is equal to the start year, and thus might fall at the
// front or the back of the default century. This only works because we adjust
// the year correctly to start with in other cases -- see subParse().
UErrorCode status = U_ZERO_ERROR;
if (ambiguousYear[0] || tztype != TZTYPE_UNK) // If this is true then the two-digit year == the default start year
{
// We need a copy of the fields, and we need to avoid triggering a call to
@ -1671,13 +1702,25 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
delete copy;
}
}
ExitParse:
ExitParse:
// Set the parsed result if local calendar is used
// instead of the input calendar
if (U_SUCCESS(status) && workCal != &cal) {
cal.setTimeZone(workCal->getTimeZone());
cal.setTime(workCal->getTime(status), status);
}
// Restore the original time zone if required
if (backupTZ != NULL) {
fCalendar->adoptTimeZone(backupTZ);
}
// If any Calendar calls failed, we pretend that we
// couldn't parse the string, when in reality this isn't quite accurate--
// we did parse it; the Calendar calls just failed.
if (U_FAILURE(status)) {
parsePos.setErrorIndex(pos);
parsePos.setIndex(start);
parsePos.setIndex(start);
}
}

View File

@ -1,6 +1,6 @@
/*
********************************************************************************
* Copyright (C) 1997-2008, International Business Machines
* Copyright (C) 1997-2009, International Business Machines
* Corporation and others. All Rights Reserved.
********************************************************************************
*
@ -245,7 +245,11 @@ public:
* occurence of the timezone pattern character 'z'.
*
* @param cal Calendar set to the date and time to be formatted
* into a date/time string.
* into a date/time string. When the calendar type is
* different from the internal calendar held by this
* DateFormat instance, the date and the time zone will
* be inherited from the input calendar, but other calendar
* field values will be calculated by the internal calendar.
* @param appendTo Output parameter to receive result.
* Result is appended to existing contents.
* @param fieldPosition On input: an alignment field, if desired (see examples above)
@ -342,7 +346,12 @@ public:
*
* @param text The date/time string to be parsed
* @param cal a Calendar set to the date and time to be formatted
* into a date/time string.
* into a date/time string. When the calendar type
* is different from the internal calendar held by this
* DateFormat instance, calendar field values will be
* parsed based on the internal calendar, then the result
* (time in milliseconds and time zone) will be set in
* this calendar.
* @param pos On input, the position at which to start parsing; on
* output, the position at which parsing terminated, or the
* start position if the parse failed.

View File

@ -1,6 +1,6 @@
/********************************************************************
* COPYRIGHT:
* Copyright (c) 1997-2008, International Business Machines Corporation and
* Copyright (c) 1997-2009, International Business Machines Corporation and
* others. All Rights Reserved.
********************************************************************/
@ -74,9 +74,10 @@ void DateFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &nam
TESTCASE(34,TestRelativeClone);
TESTCASE(35,TestHostClone);
TESTCASE(36,TestTimeZoneDisplayName);
TESTCASE(37,TestRoundtripWithCalendar);
/*
TESTCASE(37,TestRelativeError);
TESTCASE(38,TestRelativeOther);
TESTCASE(38,TestRelativeError);
TESTCASE(39,TestRelativeOther);
*/
default: name = ""; break;
}
@ -2898,6 +2899,128 @@ void DateFormatTest::TestTimeZoneDisplayName()
delete cal;
}
void DateFormatTest::TestRoundtripWithCalendar(void) {
UErrorCode status = U_ZERO_ERROR;
TimeZone *tz = TimeZone::createTimeZone("Europe/Paris");
TimeZone *gmt = TimeZone::createTimeZone("Etc/GMT");
Calendar *calendars[] = {
Calendar::createInstance(*tz, Locale("und@calendar=gregorian"), status),
Calendar::createInstance(*tz, Locale("und@calendar=buddhist"), status),
// Calendar::createInstance(*tz, Locale("und@calendar=hebrew"), status),
Calendar::createInstance(*tz, Locale("und@calendar=islamic"), status),
Calendar::createInstance(*tz, Locale("und@calendar=japanese"), status),
NULL
};
if (U_FAILURE(status)) {
errln("Failed to initialize calendars");
for (int i = 0; calendars[i] != NULL; i++) {
delete calendars[i];
}
return;
}
//FIXME The formatters commented out below are currently failing because of
// the calendar calculation problem reported by #6691
// The order of test formatters must match the order of calendars above.
DateFormat *formatters[] = {
DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale("en_US")), //calendar=gregorian
DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale("th_TH")), //calendar=buddhist
// DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale("he_IL@calendar=hebrew")),
DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale("ar_EG@calendar=islamic")),
// DateFormat::createDateTimeInstance(DateFormat::kFull, DateFormat::kFull, Locale("ja_JP@calendar=japanese")),
NULL
};
UDate d = Calendar::getNow();
UnicodeString buf;
FieldPosition fpos;
ParsePosition ppos;
for (int i = 0; formatters[i] != NULL; i++) {
buf.remove();
fpos.setBeginIndex(0);
fpos.setEndIndex(0);
calendars[i]->setTime(d, status);
// Normal case output - the given calendar matches the calendar
// used by the formatter
formatters[i]->format(*calendars[i], buf, fpos);
UnicodeString refStr(buf);
for (int j = 0; calendars[j] != NULL; j++) {
if (j == i) {
continue;
}
buf.remove();
fpos.setBeginIndex(0);
fpos.setEndIndex(0);
calendars[j]->setTime(d, status);
// Even the different calendar type is specified,
// we should get the same result.
formatters[i]->format(*calendars[j], buf, fpos);
if (refStr != buf) {
errln((UnicodeString)"FAIL: Different format result with a different calendar for the same time -"
+ "\n Reference calendar type=" + calendars[i]->getType()
+ "\n Another calendar type=" + calendars[j]->getType()
+ "\n Expected result=" + refStr
+ "\n Actual result=" + buf);
}
}
calendars[i]->setTimeZone(*gmt);
calendars[i]->clear();
ppos.setErrorIndex(-1);
ppos.setIndex(0);
// Normal case parse result - the given calendar matches the calendar
// used by the formatter
formatters[i]->parse(refStr, *calendars[i], ppos);
for (int j = 0; calendars[j] != NULL; j++) {
if (j == i) {
continue;
}
calendars[j]->setTimeZone(*gmt);
calendars[j]->clear();
ppos.setErrorIndex(-1);
ppos.setIndex(0);
// Even the different calendar type is specified,
// we should get the same time and time zone.
formatters[i]->parse(refStr, *calendars[j], ppos);
if (calendars[i]->getTime(status) != calendars[j]->getTime(status)
|| calendars[i]->getTimeZone() != calendars[j]->getTimeZone()) {
UnicodeString tzid;
errln((UnicodeString)"FAIL: Different parse result with a different calendar for the same string -"
+ "\n Reference calendar type=" + calendars[i]->getType()
+ "\n Another calendar type=" + calendars[j]->getType()
+ "\n Date string=" + refStr
+ "\n Expected time=" + calendars[i]->getTime(status)
+ "\n Expected time zone=" + calendars[i]->getTimeZone().getID(tzid)
+ "\n Actual time=" + calendars[j]->getTime(status)
+ "\n Actual time zone=" + calendars[j]->getTimeZone().getID(tzid));
}
}
if (U_FAILURE(status)) {
errln((UnicodeString)"FAIL: " + u_errorName(status));
break;
}
}
delete tz;
delete gmt;
for (int i = 0; calendars[i] != NULL; i++) {
delete calendars[i];
}
for (int i = 0; formatters[i] != NULL; i++) {
delete formatters[i];
}
}
/*
void DateFormatTest::TestRelativeError(void)
{

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.
********************************************************************/
@ -185,12 +185,15 @@ public:
void TestHostClone(void);
void TestTimeZoneDisplayName(void);
void TestRoundtripWithCalendar(void);
public:
/***
* Test Relative Dates
*/
void TestRelative(void);
void TestTimeZoneDisplayName(void);
/* void TestRelativeError(void);
void TestRelativeOther(void);
*/