ICU-6420 Fixed calendar/date symbols mismatch problem for C.
X-SVN-Rev: 25309
This commit is contained in:
parent
c6efa90f2d
commit
f682a39582
@ -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
|
||||
@ -1672,6 +1703,18 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
|
||||
}
|
||||
}
|
||||
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.
|
||||
|
@ -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.
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user