ICU-8844 Clone fCalendar as necessary so it does not get modified by format or parse methods

X-SVN-Rev: 31017
This commit is contained in:
Peter Edberg 2011-12-04 00:33:15 +00:00
parent 8087532167
commit 3a8d6c31a9
2 changed files with 63 additions and 47 deletions

View File

@ -193,11 +193,15 @@ DateFormat::format(Calendar& /* unused cal */,
UnicodeString&
DateFormat::format(UDate date, UnicodeString& appendTo, FieldPosition& fieldPosition) const {
if (fCalendar != NULL) {
// Use our calendar instance
UErrorCode ec = U_ZERO_ERROR;
fCalendar->setTime(date, ec);
if (U_SUCCESS(ec)) {
return format(*fCalendar, appendTo, fieldPosition);
// Use a clone of our calendar instance
Calendar* calClone = fCalendar->clone();
if (calClone != NULL) {
UErrorCode ec = U_ZERO_ERROR;
calClone->setTime(date, ec);
if (U_SUCCESS(ec)) {
format(*calClone, appendTo, fieldPosition);
}
delete calClone;
}
}
return appendTo;
@ -209,9 +213,13 @@ UnicodeString&
DateFormat::format(UDate date, UnicodeString& appendTo, FieldPositionIterator* posIter,
UErrorCode& status) const {
if (fCalendar != NULL) {
fCalendar->setTime(date, status);
if (U_SUCCESS(status)) {
return format(*fCalendar, appendTo, posIter, status);
Calendar* calClone = fCalendar->clone();
if (calClone != NULL) {
calClone->setTime(date, status);
if (U_SUCCESS(status)) {
format(*calClone, appendTo, posIter, status);
}
delete calClone;
}
}
return appendTo;
@ -236,28 +244,25 @@ DateFormat::parse(const UnicodeString& text,
{
UDate d = 0; // Error return UDate is 0 (the epoch)
if (fCalendar != NULL) {
int32_t start = pos.getIndex();
// Parse may update TimeZone used by the calendar.
TimeZone *tzsav = (TimeZone*)fCalendar->getTimeZone().clone();
fCalendar->clear();
parse(text, *fCalendar, pos);
if (pos.getIndex() != start) {
UErrorCode ec = U_ZERO_ERROR;
d = fCalendar->getTime(ec);
if (U_FAILURE(ec)) {
// We arrive here if fCalendar is non-lenient and there
// is an out-of-range field. We don't know which field
// was illegal so we set the error index to the start.
pos.setIndex(start);
pos.setErrorIndex(start);
d = 0;
Calendar* calClone = fCalendar->clone();
if (calClone != NULL) {
int32_t start = pos.getIndex();
calClone->clear();
parse(text, *calClone, pos);
if (pos.getIndex() != start) {
UErrorCode ec = U_ZERO_ERROR;
d = calClone->getTime(ec);
if (U_FAILURE(ec)) {
// We arrive here if fCalendar => calClone is non-lenient and
// there is an out-of-range field. We don't know which field
// was illegal so we set the error index to the start.
pos.setIndex(start);
pos.setErrorIndex(start);
d = 0;
}
}
delete calClone;
}
// Restore TimeZone
fCalendar->adoptTimeZone(tzsav);
}
return d;
}

View File

@ -830,17 +830,25 @@ UnicodeString&
SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo, FieldPositionHandler& handler,
UErrorCode& status) const
{
Calendar *workCal = &cal;
TimeZone *backupTZ = NULL;
if ( U_FAILURE(status) ) {
return appendTo;
}
Calendar* workCal = &cal;
Calendar* calClone = 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;
calClone = fCalendar->clone();
if (calClone != NULL) {
UDate t = cal.getTime(status);
calClone->setTime(t, status);
calClone->setTimeZone(cal.getTimeZone());
workCal = calClone;
} else {
status = U_MEMORY_ALLOCATION_ERROR;
return appendTo;
}
}
UBool inQuote = FALSE;
@ -885,9 +893,8 @@ SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo, FieldPositionH
subFormat(appendTo, prevCh, count, handler, *workCal, status);
}
if (backupTZ != NULL) {
// Restore the original time zone
fCalendar->adoptTimeZone(backupTZ);
if (calClone != NULL) {
delete calClone;
}
return appendTo;
@ -1875,19 +1882,24 @@ SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition&
const UnicodeString numericFormatChars(NUMERIC_FORMAT_CHARS);
TimeZone *backupTZ = NULL;
Calendar* calClone = 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)) {
calClone = fCalendar->clone();
if (calClone != NULL) {
calClone->setTime(cal.getTime(status),status);
if (U_FAILURE(status)) {
goto ExitParse;
}
calClone->setTimeZone(cal.getTimeZone());
workCal = calClone;
} else {
status = U_MEMORY_ALLOCATION_ERROR;
goto ExitParse;
}
backupTZ = fCalendar->getTimeZone().clone();
fCalendar->setTimeZone(cal.getTimeZone());
workCal = fCalendar;
}
for (int32_t i=0; i<fPattern.length(); ++i) {
@ -2187,9 +2199,8 @@ ExitParse:
cal.setTime(workCal->getTime(status), status);
}
// Restore the original time zone if required
if (backupTZ != NULL) {
fCalendar->adoptTimeZone(backupTZ);
if (calClone != NULL) {
delete calClone;
}
// If any Calendar calls failed, we pretend that we