ICU-3391 add support for YeugAZ fields; fix handling of S field; move FieldPosition selectors to udat

X-SVN-Rev: 14681
This commit is contained in:
Alan Liu 2004-03-11 14:03:37 +00:00
parent 143af6cc1b
commit 59b829f9e3

View file

@ -528,33 +528,29 @@ SimpleDateFormat::format(const Formattable& obj,
const UCalendarDateFields
SimpleDateFormat::fgPatternIndexToCalendarField[] =
{
UCAL_ERA, UCAL_YEAR, UCAL_MONTH, UCAL_DATE,
UCAL_HOUR_OF_DAY, UCAL_HOUR_OF_DAY, UCAL_MINUTE,
UCAL_SECOND, UCAL_MILLISECOND, UCAL_DAY_OF_WEEK,
UCAL_DAY_OF_YEAR, UCAL_DAY_OF_WEEK_IN_MONTH,
UCAL_WEEK_OF_YEAR, UCAL_WEEK_OF_MONTH,
UCAL_AM_PM, UCAL_HOUR, UCAL_HOUR, UCAL_ZONE_OFFSET,
UCAL_YEAR_WOY, UCAL_DOW_LOCAL,UCAL_EXTENDED_YEAR,
UCAL_JULIAN_DAY,UCAL_MILLISECONDS_IN_DAY
/*GyM*/ UCAL_ERA, UCAL_YEAR, UCAL_MONTH,
/*dkH*/ UCAL_DATE, UCAL_HOUR_OF_DAY, UCAL_HOUR_OF_DAY,
/*msS*/ UCAL_MINUTE, UCAL_SECOND, UCAL_MILLISECOND,
/*EDF*/ UCAL_DAY_OF_WEEK, UCAL_DAY_OF_YEAR, UCAL_DAY_OF_WEEK_IN_MONTH,
/*wWa*/ UCAL_WEEK_OF_YEAR, UCAL_WEEK_OF_MONTH, UCAL_AM_PM,
/*hKz*/ UCAL_HOUR, UCAL_HOUR, UCAL_ZONE_OFFSET,
/*Yeu*/ UCAL_YEAR_WOY, UCAL_DOW_LOCAL, UCAL_EXTENDED_YEAR,
/*gAZ*/ UCAL_JULIAN_DAY, UCAL_MILLISECONDS_IN_DAY, UCAL_ZONE_OFFSET
};
// Map index into pattern character string to DateFormat field number
const DateFormat::EField
const UDateFormatField
SimpleDateFormat::fgPatternIndexToDateFormatField[] = {
DateFormat::kEraField, DateFormat::kYearField, DateFormat::kMonthField,
DateFormat::kDateField, DateFormat::kHourOfDay1Field,
DateFormat::kHourOfDay0Field, DateFormat::kMinuteField,
DateFormat::kSecondField, DateFormat::kMillisecondField,
DateFormat::kDayOfWeekField, DateFormat::kDayOfYearField,
DateFormat::kDayOfWeekInMonthField, DateFormat::kWeekOfYearField,
DateFormat::kWeekOfMonthField, DateFormat::kAmPmField,
DateFormat::kHour1Field, DateFormat::kHour0Field,
DateFormat::kTimezoneField, DateFormat::kYearWOYField,
DateFormat::kDOWLocalField, DateFormat::kExtendedYearField,
DateFormat::kJulianDayField, DateFormat::kMillisecondsInDayField
/*GyM*/ UDAT_ERA_FIELD, UDAT_YEAR_FIELD, UDAT_MONTH_FIELD,
/*dkH*/ UDAT_DATE_FIELD, UDAT_HOUR_OF_DAY1_FIELD, UDAT_HOUR_OF_DAY0_FIELD,
/*msS*/ UDAT_MINUTE_FIELD, UDAT_SECOND_FIELD, UDAT_FRACTIONAL_SECOND_FIELD,
/*EDF*/ UDAT_DAY_OF_WEEK_FIELD, UDAT_DAY_OF_YEAR_FIELD, UDAT_DAY_OF_WEEK_IN_MONTH_FIELD,
/*wWa*/ UDAT_WEEK_OF_YEAR_FIELD, UDAT_WEEK_OF_MONTH_FIELD, UDAT_AM_PM_FIELD,
/*hKz*/ UDAT_HOUR1_FIELD, UDAT_HOUR0_FIELD, UDAT_TIMEZONE_FIELD,
/*Yeu*/ UDAT_YEAR_WOY_FIELD, UDAT_DOW_LOCAL_FIELD, UDAT_EXTENDED_YEAR_FIELD,
/*gAZ*/ UDAT_JULIAN_DAY_FIELD, UDAT_MILLISECONDS_IN_DAY_FIELD, UDAT_TIMEZONE_RFC_FIELD
};
//----------------------------------------------------------------------
void
@ -573,7 +569,7 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
// text for an individual pattern symbol (e.g., "HH" or "yyyy")
UChar *patternCharPtr = u_strchr(DateFormatSymbols::getPatternUChars(), ch);
EField patternCharIndex;
UDateFormatField patternCharIndex;
const int32_t maxIntCount = 10;
int32_t beginOffset = appendTo.length();
@ -584,7 +580,7 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
return;
}
patternCharIndex = (EField)(patternCharPtr - DateFormatSymbols::getPatternUChars());
patternCharIndex = (UDateFormatField)(patternCharPtr - DateFormatSymbols::getPatternUChars());
UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex];
int32_t value = cal.get(field, status);
if (U_FAILURE(status)) {
@ -594,13 +590,13 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
switch (patternCharIndex) {
// for any "G" symbol, write out the appropriate era string
case kEraField:
case UDAT_ERA_FIELD:
appendTo += fSymbols->fEras[value];
break;
// for "yyyy", write out the whole year; for "yy", write out the last 2 digits
case kYearField:
case kYearWOYField:
case UDAT_YEAR_FIELD:
case UDAT_YEAR_WOY_FIELD:
if (count >= 4)
zeroPaddingNumber(appendTo, value, 4, maxIntCount);
else if(count == 1)
@ -612,7 +608,7 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
// for "MMMM", write out the whole month name, for "MMM", write out the month
// abbreviation, for "M" or "MM", write out the month as a number with the
// appropriate number of digits
case kMonthField:
case UDAT_MONTH_FIELD:
if (count >= 4)
appendTo += fSymbols->fMonths[value];
else if (count == 3)
@ -622,27 +618,34 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
break;
// for "k" and "kk", write out the hour, adjusting midnight to appear as "24"
case kHourOfDay1Field:
case UDAT_HOUR_OF_DAY1_FIELD:
if (value == 0)
zeroPaddingNumber(appendTo, cal.getMaximum(UCAL_HOUR_OF_DAY) + 1, count, maxIntCount);
else
zeroPaddingNumber(appendTo, value, count, maxIntCount);
break;
// for "SS" and "S", we want to truncate digits so that you still see the MOST
// significant digits rather than the LEAST (as is the case with the year)
case kMillisecondField:
if (count > 3)
count = 3;
else if (count == 2)
value = value / 10;
else if (count == 1)
value = value / 100;
zeroPaddingNumber(appendTo, value, count, maxIntCount);
case UDAT_FRACTIONAL_SECOND_FIELD:
// Fractional seconds left-justify
{
fNumberFormat->setMinimumIntegerDigits((count > 3) ? 3 : count);
fNumberFormat->setMaximumIntegerDigits(maxIntCount);
if (count == 1) {
value = (value + 50) / 100;
} else if (count == 2) {
value = (value + 5) / 10;
}
FieldPosition p(0);
fNumberFormat->format(value, appendTo, p);
if (count > 3) {
fNumberFormat->setMinimumIntegerDigits(count - 3);
fNumberFormat->format((int32_t)0, appendTo, p);
}
}
break;
// for "EEEE", write out the day-of-the-week name; otherwise, use the abbreviation
case kDayOfWeekField:
case UDAT_DAY_OF_WEEK_FIELD:
if (count >= 4)
appendTo += fSymbols->fWeekdays[value];
else
@ -650,13 +653,13 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
break;
// for and "a" symbol, write out the whole AM/PM string
case kAmPmField:
case UDAT_AM_PM_FIELD:
appendTo += fSymbols->fAmPms[value];
break;
// for "h" and "hh", write out the hour, adjusting noon and midnight to show up
// as "12"
case kHour1Field:
case UDAT_HOUR1_FIELD:
if (value == 0)
zeroPaddingNumber(appendTo, cal.getLeastMaximum(UCAL_HOUR) + 1, count, maxIntCount);
else
@ -669,7 +672,7 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
// since the name will be different). If we don't have a localized time zone name,
// then the time zone shows up as "GMT+hh:mm" or "GMT-hh:mm" (where "hh:mm" is the
// offset from GMT) regardless of how many z's were in the pattern symbol
case kTimezoneField: {
case UDAT_TIMEZONE_FIELD: {
UnicodeString str;
int32_t zoneIndex = fSymbols->getZoneIndex(cal.getTimeZone().getID(str));
if (zoneIndex == -1) {
@ -702,30 +705,34 @@ SimpleDateFormat::subFormat(UnicodeString &appendTo,
}
break;
case 23: // 'Z' - TIMEZONE_RFC
{
UChar sign = 43/*'+'*/;
value = (cal.get(UCAL_ZONE_OFFSET, status) +
cal.get(UCAL_DST_OFFSET, status)) / U_MILLIS_PER_MINUTE;
if (value < 0) {
value = -value;
sign = 45/*'-'*/;
}
value = (value / 3) * 5 + (value % 60); // minutes => KKmm
appendTo += sign;
zeroPaddingNumber(appendTo, value, 4, 4);
}
break;
// all of the other pattern symbols can be formatted as simple numbers with
// appropriate zero padding
default:
// case kDateField:
// case kHourOfDay0Field:
// case kMinuteField:
// case kSecondField:
// case kDayOfYearField:
// case kDayOfWeekInMonthField:
// case kWeekOfYearField:
// case kWeekOfMonthField:
// case kHour0Field:
// case kDOWLocalField:
zeroPaddingNumber(appendTo, value, count, maxIntCount);
break;
}
// if the field we're formatting is the one the FieldPosition says it's interested
// in, fill in the FieldPosition with this field's positions
if (pos.getField() == fgPatternIndexToDateFormatField[patternCharIndex]) {
if (pos.getBeginIndex() == 0 && pos.getEndIndex() == 0) {
pos.setBeginIndex(beginOffset);
pos.setEndIndex(appendTo.length());
}
if (pos.getBeginIndex() == pos.getEndIndex() &&
pos.getField() == fgPatternIndexToDateFormatField[patternCharIndex]) {
pos.setBeginIndex(beginOffset);
pos.setEndIndex(appendTo.length());
}
}
@ -1089,7 +1096,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
return -start;
}
patternCharIndex = (EField)(patternCharPtr - DateFormatSymbols::getPatternUChars());
patternCharIndex = (UDateFormatField)(patternCharPtr - DateFormatSymbols::getPatternUChars());
UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex];
@ -1111,13 +1118,14 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
// a number value. We handle further, more generic cases below. We need
// to handle some of them here because some fields require extra processing on
// the parsed value.
if (patternCharIndex == kHourOfDay1Field /*HOUR_OF_DAY1_FIELD*/ ||
patternCharIndex == kHour1Field /*HOUR1_FIELD*/ ||
(patternCharIndex == kMonthField /*MONTH_FIELD*/ && count <= 2) ||
patternCharIndex == kYearField /*YEAR*/ ||
patternCharIndex == kYearWOYField)
if (patternCharIndex == UDAT_HOUR_OF_DAY1_FIELD ||
patternCharIndex == UDAT_HOUR1_FIELD ||
(patternCharIndex == UDAT_MONTH_FIELD && count <= 2) ||
patternCharIndex == UDAT_YEAR_FIELD ||
patternCharIndex == UDAT_YEAR_WOY_FIELD ||
patternCharIndex == UDAT_FRACTIONAL_SECOND_FIELD)
{
int32_t parseStart = pos.getIndex(); // WORK AROUND BUG IN NUMBER FORMAT IN 1.2B3
int32_t parseStart = pos.getIndex();
// It would be good to unify this with the obeyCount logic below,
// but that's going to be difficult.
const UnicodeString* src;
@ -1132,15 +1140,14 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
}
parseInt(*src, number, pos, allowNegative);
if (pos.getIndex() == parseStart)
// WORK AROUND BUG IN NUMBER FORMAT IN 1.2B3
return -start;
value = number.getLong();
}
switch (patternCharIndex) {
case kEraField:
case UDAT_ERA_FIELD:
return matchString(text, start, UCAL_ERA, fSymbols->fEras, fSymbols->fErasCount, cal);
case kYearField:
case UDAT_YEAR_FIELD:
// 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
@ -1168,8 +1175,8 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
}
cal.set(UCAL_YEAR, value);
return pos.getIndex();
case kYearWOYField:
// Comment is the same as for kYearFields - look above
case UDAT_YEAR_WOY_FIELD:
// Comment is the same as for UDAT_Year_FIELDs - look above
if (count <= 2 && (pos.getIndex() - start) == 2
&& u_isdigit(text.charAt(start))
&& u_isdigit(text.charAt(start+1))
@ -1182,7 +1189,7 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
}
cal.set(UCAL_YEAR_WOY, value);
return pos.getIndex();
case kMonthField:
case UDAT_MONTH_FIELD:
if (count <= 2) // i.e., M or MM.
{
// Don't want to parse the month if it is a string
@ -1204,13 +1211,31 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
return matchString(text, start, UCAL_MONTH,
fSymbols->fShortMonths, fSymbols->fShortMonthsCount, cal);
}
case kHourOfDay1Field:
case UDAT_HOUR_OF_DAY1_FIELD:
// [We computed 'value' above.]
if (value == cal.getMaximum(UCAL_HOUR_OF_DAY) + 1)
value = 0;
cal.set(UCAL_HOUR_OF_DAY, value);
return pos.getIndex();
case kDayOfWeekField:
case UDAT_FRACTIONAL_SECOND_FIELD:
// Fractional seconds left-justify
i = pos.getIndex() - start;
if (i < 3) {
while (i < 3) {
value *= 10;
i++;
}
} else {
int32_t a = 1;
while (i > 3) {
a *= 10;
i--;
}
value = (value + (a>>1)) / a;
}
cal.set(UCAL_MILLISECOND, value);
return pos.getIndex();
case UDAT_DAY_OF_WEEK_FIELD:
{
// Want to be able to parse both short and long forms.
// Try count == 4 (DDDD) first:
@ -1222,15 +1247,16 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
return matchString(text, start, UCAL_DAY_OF_WEEK,
fSymbols->fShortWeekdays, fSymbols->fShortWeekdaysCount, cal);
}
case kAmPmField:
case UDAT_AM_PM_FIELD:
return matchString(text, start, UCAL_AM_PM, fSymbols->fAmPms, fSymbols->fAmPmsCount, cal);
case kHour1Field:
case UDAT_HOUR1_FIELD:
// [We computed 'value' above.]
if (value == cal.getLeastMaximum(UCAL_HOUR)+1)
value = 0;
cal.set(UCAL_HOUR, value);
return pos.getIndex();
case kTimezoneField:
case UDAT_TIMEZONE_FIELD:
case UDAT_TIMEZONE_RFC_FIELD:
{
// First try to parse generic forms such as GMT-07:00. Do this first
// in case localized DateFormatZoneData contains the string "GMT"
@ -1271,23 +1297,19 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
// Look for hours:minutes or hhmm.
pos.setIndex(pos.getIndex() + 1);
// WORK AROUND BUG IN NUMBER FORMAT IN 1.2B3
int32_t parseStart = pos.getIndex();
Formattable tzNumber;
fNumberFormat->parse(text, tzNumber, pos);
if( pos.getIndex() == parseStart) {
// WORK AROUND BUG IN NUMBER FORMAT IN 1.2B3
return -start;
}
if( text[pos.getIndex()] == 0x003A /*':'*/ ) {
// This is the hours:minutes case
offset = tzNumber.getLong() * 60;
pos.setIndex(pos.getIndex() + 1);
// WORK AROUND BUG IN NUMBER FORMAT IN 1.2B3
parseStart = pos.getIndex();
fNumberFormat->parse(text, tzNumber, pos);
if( pos.getIndex() == parseStart) {
// WORK AROUND BUG IN NUMBER FORMAT IN 1.2B3
return -start;
}
offset += tzNumber.getLong();
@ -1343,12 +1365,10 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
if(U_FAILURE(status))
return -start;
fmt.setParseIntegerOnly(TRUE);
// WORK AROUND BUG IN NUMBER FORMAT IN 1.2B3
int32_t parseStart = pos.getIndex();
Formattable tzNumber;
fmt.parse( text, tzNumber, pos );
if( pos.getIndex() == parseStart) {
// WORK AROUND BUG IN NUMBER FORMAT IN 1.2B3
return -start; // Wasn't actually a number.
}
offset = tzNumber.getLong();
@ -1385,21 +1405,8 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
return -start;
}
default:
// case 3: // 'd' - DATE
// case 5: // 'H' - HOUR_OF_DAY:0-based. eg, 23:59 + 1 hour =>> 00:59
// case 6: // 'm' - MINUTE
// case 7: // 's' - SECOND
// case 8: // 'S' - MILLISECOND
// case 10: // 'D' - DAY_OF_YEAR
// case 11: // 'F' - DAY_OF_WEEK_IN_MONTH
// case 12: // 'w' - WEEK_OF_YEAR
// case 13: // 'W' - WEEK_OF_MONTH
// case 16: // 'K' - HOUR: 0-based. eg, 11PM + 1 hour =>> 0 AM
// 'e' - DOW_LOCAL
// WORK AROUND BUG IN NUMBER FORMAT IN 1.2B3
int32_t parseStart = pos.getIndex();
// Handle "generic" fields
int32_t parseStart = pos.getIndex();
const UnicodeString* src;
if (obeyCount) {
if ((start+count) > text.length()) {
@ -1412,7 +1419,6 @@ int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UC
}
parseInt(*src, number, pos, allowNegative);
if (pos.getIndex() != parseStart) {
// WORK AROUND BUG IN NUMBER FORMAT IN 1.2B3
cal.set(field, number.getLong());
return pos.getIndex();
}