X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/249c4c5ea9376c24572daf9c2effa7484a282f14..3d1f044b704633e2e541231cd17ae9ecf9ad5c7a:/icuSources/i18n/dtitvfmt.cpp diff --git a/icuSources/i18n/dtitvfmt.cpp b/icuSources/i18n/dtitvfmt.cpp index 1a3cc986..ba6001f5 100644 --- a/icuSources/i18n/dtitvfmt.cpp +++ b/icuSources/i18n/dtitvfmt.cpp @@ -22,13 +22,15 @@ #include "unicode/calendar.h" #include "unicode/dtptngen.h" #include "unicode/dtitvinf.h" -#include "unicode/udateintervalformat.h" #include "unicode/simpleformatter.h" #include "cmemory.h" #include "cstring.h" #include "dtitv_impl.h" #include "mutex.h" #include "uresimp.h" +#include "formattedval_impl.h" +// Apple addition +#include "unicode/udateintervalformat.h" #ifdef DTITVFMT_DEBUG #include @@ -66,12 +68,26 @@ static const UChar gLaterFirstPrefix[] = {LOW_L, LOW_A, LOW_T, LOW_E, LOW_S,LOW_ static const UChar gEarlierFirstPrefix[] = {LOW_E, LOW_A, LOW_R, LOW_L, LOW_I, LOW_E, LOW_S, LOW_T, CAP_F, LOW_I, LOW_R, LOW_S, LOW_T, COLON}; +class FormattedDateIntervalData : public FormattedValueFieldPositionIteratorImpl { +public: + FormattedDateIntervalData(UErrorCode& status) : FormattedValueFieldPositionIteratorImpl(5, status) {} + virtual ~FormattedDateIntervalData(); +}; + +FormattedDateIntervalData::~FormattedDateIntervalData() = default; + +UPRV_FORMATTED_VALUE_SUBCLASS_AUTO_IMPL(FormattedDateInterval) + + UOBJECT_DEFINE_RTTI_IMPLEMENTATION(DateIntervalFormat) // Mutex, protects access to fDateFormat, fFromCalendar and fToCalendar. // Needed because these data members are modified by const methods of DateIntervalFormat. -static UMutex gFormatterMutex = U_MUTEX_INITIALIZER; +static UMutex *gFormatterMutex() { + static UMutex *m = STATIC_NEW(UMutex); + return m; +} DateIntervalFormat* U_EXPORT2 DateIntervalFormat::createInstance(const UnicodeString& skeleton, @@ -129,7 +145,8 @@ DateIntervalFormat::DateIntervalFormat() fDatePattern(NULL), fTimePattern(NULL), fDateTimeFormat(NULL), - fMinimizeType(UDTITVFMT_MINIMIZE_NONE) + fMinimizeType(UDTITVFMT_MINIMIZE_NONE), + fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE) {} @@ -143,7 +160,8 @@ DateIntervalFormat::DateIntervalFormat(const DateIntervalFormat& itvfmt) fDatePattern(NULL), fTimePattern(NULL), fDateTimeFormat(NULL), - fMinimizeType(UDTITVFMT_MINIMIZE_NONE) { + fMinimizeType(UDTITVFMT_MINIMIZE_NONE), + fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE) { *this = itvfmt; } @@ -159,7 +177,7 @@ DateIntervalFormat::operator=(const DateIntervalFormat& itvfmt) { delete fTimePattern; delete fDateTimeFormat; { - Mutex lock(&gFormatterMutex); + Mutex lock(gFormatterMutex()); if ( itvfmt.fDateFormat ) { fDateFormat = (SimpleDateFormat*)itvfmt.fDateFormat->clone(); } else { @@ -190,6 +208,8 @@ DateIntervalFormat::operator=(const DateIntervalFormat& itvfmt) { fDatePattern = (itvfmt.fDatePattern)? (UnicodeString*)itvfmt.fDatePattern->clone(): NULL; fTimePattern = (itvfmt.fTimePattern)? (UnicodeString*)itvfmt.fTimePattern->clone(): NULL; fDateTimeFormat = (itvfmt.fDateTimeFormat)? (UnicodeString*)itvfmt.fDateTimeFormat->clone(): NULL; + fMinimizeType = itvfmt.fMinimizeType; + fCapitalizationContext = itvfmt.fCapitalizationContext; } return *this; } @@ -221,7 +241,7 @@ DateIntervalFormat::operator==(const Format& other) const { if ((fInfo != fmt->fInfo) && (fInfo == NULL || fmt->fInfo == NULL)) {return FALSE;} if (fInfo && fmt->fInfo && (*fInfo != *fmt->fInfo )) {return FALSE;} { - Mutex lock(&gFormatterMutex); + Mutex lock(gFormatterMutex()); if (fDateFormat != fmt->fDateFormat && (fDateFormat == NULL || fmt->fDateFormat == NULL)) {return FALSE;} if (fDateFormat && fmt->fDateFormat && (*fDateFormat != *fmt->fDateFormat)) {return FALSE;} } @@ -241,6 +261,8 @@ DateIntervalFormat::operator==(const Format& other) const { if (fIntervalPatterns[i].secondPart != fmt->fIntervalPatterns[i].secondPart ) {return FALSE;} if (fIntervalPatterns[i].laterDateFirst != fmt->fIntervalPatterns[i].laterDateFirst) {return FALSE;} } + if (fMinimizeType != fmt->fMinimizeType) {return FALSE;} + if (fCapitalizationContext != fmt->fCapitalizationContext) {return FALSE;} return TRUE; } @@ -274,15 +296,51 @@ DateIntervalFormat::format(const DateInterval* dtInterval, if ( U_FAILURE(status) ) { return appendTo; } - if (fFromCalendar == NULL || fToCalendar == NULL || fDateFormat == NULL || fInfo == NULL) { + if (fDateFormat == NULL || fInfo == NULL) { status = U_INVALID_STATE_ERROR; return appendTo; } - Mutex lock(&gFormatterMutex); - fFromCalendar->setTime(dtInterval->getFromDate(), status); - fToCalendar->setTime(dtInterval->getToDate(), status); - return formatImpl(*fFromCalendar, *fToCalendar, appendTo,fieldPosition, status); + FieldPositionOnlyHandler handler(fieldPosition); + handler.setAcceptFirstOnly(TRUE); + int8_t ignore; + + Mutex lock(gFormatterMutex()); + return formatIntervalImpl(*dtInterval, appendTo, ignore, handler, status); +} + + +FormattedDateInterval DateIntervalFormat::formatToValue( + const DateInterval& dtInterval, + UErrorCode& status) const { + LocalPointer result(new FormattedDateIntervalData(status), status); + if (U_FAILURE(status)) { + return FormattedDateInterval(status); + } + UnicodeString string; + int8_t firstIndex; + auto handler = result->getHandler(status); + handler.setCategory(UFIELD_CATEGORY_DATE); + { + Mutex lock(gFormatterMutex()); + formatIntervalImpl(dtInterval, string, firstIndex, handler, status); + } + handler.getError(status); + result->appendString(string, status); + if (U_FAILURE(status)) { + return FormattedDateInterval(status); + } + + // Compute the span fields and sort them into place: + if (firstIndex != -1) { + result->addOverlapSpans(UFIELD_CATEGORY_DATE_INTERVAL_SPAN, firstIndex, status); + if (U_FAILURE(status)) { + return FormattedDateInterval(status); + } + result->sort(); + } + + return FormattedDateInterval(result.orphan()); } @@ -292,8 +350,63 @@ DateIntervalFormat::format(Calendar& fromCalendar, UnicodeString& appendTo, FieldPosition& pos, UErrorCode& status) const { - Mutex lock(&gFormatterMutex); - return formatImpl(fromCalendar, toCalendar, appendTo, pos, status); + FieldPositionOnlyHandler handler(pos); + handler.setAcceptFirstOnly(TRUE); + int8_t ignore; + + Mutex lock(gFormatterMutex()); + return formatImpl(fromCalendar, toCalendar, appendTo, ignore, handler, status); +} + + +FormattedDateInterval DateIntervalFormat::formatToValue( + Calendar& fromCalendar, + Calendar& toCalendar, + UErrorCode& status) const { + LocalPointer result(new FormattedDateIntervalData(status), status); + if (U_FAILURE(status)) { + return FormattedDateInterval(status); + } + UnicodeString string; + int8_t firstIndex; + auto handler = result->getHandler(status); + handler.setCategory(UFIELD_CATEGORY_DATE); + { + Mutex lock(gFormatterMutex()); + formatImpl(fromCalendar, toCalendar, string, firstIndex, handler, status); + } + handler.getError(status); + result->appendString(string, status); + if (U_FAILURE(status)) { + return FormattedDateInterval(status); + } + + // Compute the span fields and sort them into place: + if (firstIndex != -1) { + result->addOverlapSpans(UFIELD_CATEGORY_DATE_INTERVAL_SPAN, firstIndex, status); + result->sort(); + } + + return FormattedDateInterval(result.orphan()); +} + + +UnicodeString& DateIntervalFormat::formatIntervalImpl( + const DateInterval& dtInterval, + UnicodeString& appendTo, + int8_t& firstIndex, + FieldPositionHandler& fphandler, + UErrorCode& status) const { + if (U_FAILURE(status)) { + return appendTo; + } + if (fFromCalendar == nullptr || fToCalendar == nullptr) { + status = U_INVALID_STATE_ERROR; + return appendTo; + } + fFromCalendar->setTime(dtInterval.getFromDate(), status); + fToCalendar->setTime(dtInterval.getToDate(), status); + return formatImpl(*fFromCalendar, *fToCalendar, appendTo, firstIndex, fphandler, status); } @@ -301,12 +414,16 @@ UnicodeString& DateIntervalFormat::formatImpl(Calendar& fromCalendar, Calendar& toCalendar, UnicodeString& appendTo, - FieldPosition& pos, + int8_t& firstIndex, + FieldPositionHandler& fphandler, UErrorCode& status) const { if ( U_FAILURE(status) ) { return appendTo; } + // Initialize firstIndex to -1 (single date, no range) + firstIndex = -1; + // not support different calendar types and time zones //if ( fromCalendar.getType() != toCalendar.getType() ) { if ( !fromCalendar.isEquivalentTo(toCalendar) ) { @@ -386,7 +503,8 @@ DateIntervalFormat::formatImpl(Calendar& fromCalendar, /* ignore the millisecond etc. small fields' difference. * use single date when all the above are the same. */ - return fDateFormat->format(fromCalendar, appendTo, pos); + fDateFormat->setContext(fCapitalizationContext, status); + return fDateFormat->_format(fromCalendar, appendTo, fphandler, status); } UBool fromToOnSameDay = (field==UCAL_AM_PM || field==UCAL_HOUR || field==UCAL_MINUTE || field==UCAL_SECOND); @@ -403,9 +521,10 @@ DateIntervalFormat::formatImpl(Calendar& fromCalendar, * the smallest calendar field in pattern, * return single date format. */ - return fDateFormat->format(fromCalendar, appendTo, pos); + fDateFormat->setContext(fCapitalizationContext, status); + return fDateFormat->_format(fromCalendar, appendTo, fphandler, status); } - return fallbackFormat(fromCalendar, toCalendar, fromToOnSameDay, appendTo, pos, status); + return fallbackFormat(fromCalendar, toCalendar, fromToOnSameDay, appendTo, firstIndex, fphandler, status); } // If the first part in interval pattern is empty, // the 2nd part of it saves the full-pattern used in fall-back. @@ -415,7 +534,7 @@ DateIntervalFormat::formatImpl(Calendar& fromCalendar, UnicodeString originalPattern; fDateFormat->toPattern(originalPattern); fDateFormat->applyPattern(intervalPattern.secondPart); - appendTo = fallbackFormat(fromCalendar, toCalendar, fromToOnSameDay, appendTo, pos, status); + appendTo = fallbackFormat(fromCalendar, toCalendar, fromToOnSameDay, appendTo, firstIndex, fphandler, status); fDateFormat->applyPattern(originalPattern); return appendTo; } @@ -424,24 +543,24 @@ DateIntervalFormat::formatImpl(Calendar& fromCalendar, if ( intervalPattern.laterDateFirst ) { firstCal = &toCalendar; secondCal = &fromCalendar; + firstIndex = 1; } else { firstCal = &fromCalendar; secondCal = &toCalendar; + firstIndex = 0; } // break the interval pattern into 2 parts, // first part should not be empty, UnicodeString originalPattern; fDateFormat->toPattern(originalPattern); fDateFormat->applyPattern(intervalPattern.firstPart); - fDateFormat->format(*firstCal, appendTo, pos); + fDateFormat->setContext(fCapitalizationContext, status); + fDateFormat->_format(*firstCal, appendTo, fphandler, status); + if ( !intervalPattern.secondPart.isEmpty() ) { fDateFormat->applyPattern(intervalPattern.secondPart); - FieldPosition otherPos; - otherPos.setField(pos.getField()); - fDateFormat->format(*secondCal, appendTo, otherPos); - if (pos.getEndIndex() == 0 && otherPos.getEndIndex() > 0) { - pos = otherPos; - } + fDateFormat->setContext(UDISPCTX_CAPITALIZATION_NONE, status); + fDateFormat->_format(*secondCal, appendTo, fphandler, status); } fDateFormat->applyPattern(originalPattern); return appendTo; @@ -532,7 +651,7 @@ const TimeZone& DateIntervalFormat::getTimeZone() const { if (fDateFormat != NULL) { - Mutex lock(&gFormatterMutex); + Mutex lock(gFormatterMutex()); return fDateFormat->getTimeZone(); } // If fDateFormat is NULL (unexpected), create default timezone. @@ -554,6 +673,30 @@ DateIntervalFormat::setAttribute(UDateIntervalFormatAttribute attr, } } +void +DateIntervalFormat::setContext(UDisplayContext value, UErrorCode& status) +{ + if (U_FAILURE(status)) + return; + if ( (UDisplayContextType)((uint32_t)value >> 8) == UDISPCTX_TYPE_CAPITALIZATION ) { + fCapitalizationContext = value; + } else { + status = U_ILLEGAL_ARGUMENT_ERROR; + } +} + +UDisplayContext +DateIntervalFormat::getContext(UDisplayContextType type, UErrorCode& status) const +{ + if (U_FAILURE(status)) + return (UDisplayContext)0; + if (type != UDISPCTX_TYPE_CAPITALIZATION) { + status = U_ILLEGAL_ARGUMENT_ERROR; + return (UDisplayContext)0; + } + return fCapitalizationContext; +} + DateIntervalFormat::DateIntervalFormat(const Locale& locale, DateIntervalInfo* dtItvInfo, const UnicodeString* skeleton, @@ -566,7 +709,8 @@ DateIntervalFormat::DateIntervalFormat(const Locale& locale, fDatePattern(NULL), fTimePattern(NULL), fDateTimeFormat(NULL), - fMinimizeType(UDTITVFMT_MINIMIZE_NONE) + fMinimizeType(UDTITVFMT_MINIMIZE_NONE), + fCapitalizationContext(UDISPCTX_CAPITALIZATION_NONE) { LocalPointer info(dtItvInfo, status); LocalPointer dtfmt(static_cast( @@ -933,8 +1077,7 @@ DateIntervalFormat::getDateTimeSkeleton(const UnicodeString& skeleton, if ( MCount < 3 ) { normalizedDateSkeleton.append(CAP_M); } else { - int32_t i; - for ( i = 0; i < MCount && i < MAX_M_COUNT; ++i ) { + for ( int32_t j = 0; j < MCount && j < MAX_M_COUNT; ++j) { normalizedDateSkeleton.append(CAP_M); } } @@ -943,8 +1086,7 @@ DateIntervalFormat::getDateTimeSkeleton(const UnicodeString& skeleton, if ( ECount <= 3 ) { normalizedDateSkeleton.append(CAP_E); } else { - int32_t i; - for ( i = 0; i < ECount && i < MAX_E_COUNT; ++i ) { + for ( int32_t j = 0; j < ECount && j < MAX_E_COUNT; ++j ) { normalizedDateSkeleton.append(CAP_E); } } @@ -1083,7 +1225,6 @@ DateIntervalFormat::setSeparateDateTimePtn( setIntervalPattern(UCAL_ERA, skeleton, bestSkeleton, differenceInfo, &extendedSkeleton, &extendedBestSkeleton); } else { - // what about seconds handling? setIntervalPattern(UCAL_MINUTE, skeleton, bestSkeleton, differenceInfo); setIntervalPattern(UCAL_HOUR, skeleton, bestSkeleton, differenceInfo); setIntervalPattern(UCAL_AM_PM, skeleton, bestSkeleton, differenceInfo); @@ -1355,40 +1496,41 @@ DateIntervalFormat::splitPatternInto2Part(const UnicodeString& intervalPattern) return (i - count); } -static const UChar bracketedZero[] = {0x7B,0x30,0x7D}; -static const UChar bracketedOne[] = {0x7B,0x31,0x7D}; - -void -DateIntervalFormat::adjustPosition(UnicodeString& combiningPattern, // has {0} and {1} in it - UnicodeString& pat0, FieldPosition& pos0, // pattern and pos corresponding to {0} - UnicodeString& pat1, FieldPosition& pos1, // pattern and pos corresponding to {1} - FieldPosition& posResult) { - int32_t index0 = combiningPattern.indexOf(bracketedZero, 3, 0); - int32_t index1 = combiningPattern.indexOf(bracketedOne, 3, 0); - if (index0 < 0 || index1 < 0) { +void DateIntervalFormat::fallbackFormatRange( + Calendar& fromCalendar, + Calendar& toCalendar, + UnicodeString& appendTo, + int8_t& firstIndex, + FieldPositionHandler& fphandler, + UErrorCode& status) const { + UnicodeString fallbackPattern; + fInfo->getFallbackIntervalPattern(fallbackPattern); + SimpleFormatter sf(fallbackPattern, 2, 2, status); + if (U_FAILURE(status)) { return; } - int32_t placeholderLen = 3; // length of "{0}" or "{1}" - if (index0 < index1) { - if (pos0.getEndIndex() > 0) { - posResult.setBeginIndex(pos0.getBeginIndex() + index0); - posResult.setEndIndex(pos0.getEndIndex() + index0); - } else if (pos1.getEndIndex() > 0) { - // here index1 >= 3 - index1 += pat0.length() - placeholderLen; // adjust for pat0 replacing {0} - posResult.setBeginIndex(pos1.getBeginIndex() + index1); - posResult.setEndIndex(pos1.getEndIndex() + index1); - } + int32_t offsets[2]; + UnicodeString patternBody = sf.getTextWithNoArguments(offsets, 2); + + // TODO(ICU-20406): Use SimpleFormatter Iterator interface when available. + // The context for the first of the _format calls in each pair is set by caller. + // This function always leaves _format context as UDISPCTX_CAPITALIZATION_NONE. + if (offsets[0] < offsets[1]) { + firstIndex = 0; + appendTo.append(patternBody.tempSubStringBetween(0, offsets[0])); + fDateFormat->_format(fromCalendar, appendTo, fphandler, status); + appendTo.append(patternBody.tempSubStringBetween(offsets[0], offsets[1])); + fDateFormat->setContext(UDISPCTX_CAPITALIZATION_NONE, status); + fDateFormat->_format(toCalendar, appendTo, fphandler, status); + appendTo.append(patternBody.tempSubStringBetween(offsets[1])); } else { - if (pos1.getEndIndex() > 0) { - posResult.setBeginIndex(pos1.getBeginIndex() + index1); - posResult.setEndIndex(pos1.getEndIndex() + index1); - } else if (pos0.getEndIndex() > 0) { - // here index0 >= 3 - index0 += pat1.length() - placeholderLen; // adjust for pat1 replacing {1} - posResult.setBeginIndex(pos0.getBeginIndex() + index0); - posResult.setEndIndex(pos0.getEndIndex() + index0); - } + firstIndex = 1; + appendTo.append(patternBody.tempSubStringBetween(0, offsets[1])); + fDateFormat->_format(toCalendar, appendTo, fphandler, status); + appendTo.append(patternBody.tempSubStringBetween(offsets[1], offsets[0])); + fDateFormat->setContext(UDISPCTX_CAPITALIZATION_NONE, status); + fDateFormat->_format(fromCalendar, appendTo, fphandler, status); + appendTo.append(patternBody.tempSubStringBetween(offsets[0])); } } @@ -1397,53 +1539,54 @@ DateIntervalFormat::fallbackFormat(Calendar& fromCalendar, Calendar& toCalendar, UBool fromToOnSameDay, // new UnicodeString& appendTo, - FieldPosition& pos, + int8_t& firstIndex, + FieldPositionHandler& fphandler, UErrorCode& status) const { if ( U_FAILURE(status) ) { return appendTo; } - UnicodeString fullPattern; // for saving the pattern in fDateFormat + UBool formatDatePlusTimeRange = (fromToOnSameDay && fDatePattern && fTimePattern); - // the fall back if (formatDatePlusTimeRange) { + SimpleFormatter sf(*fDateTimeFormat, 2, 2, status); + if (U_FAILURE(status)) { + return appendTo; + } + int32_t offsets[2]; + UnicodeString patternBody = sf.getTextWithNoArguments(offsets, 2); + + UnicodeString fullPattern; // for saving the pattern in fDateFormat fDateFormat->toPattern(fullPattern); // save current pattern, restore later - fDateFormat->applyPattern(*fTimePattern); - } - FieldPosition otherPos; - otherPos.setField(pos.getField()); - UnicodeString earlierDate; - fDateFormat->format(fromCalendar, earlierDate, pos); - UnicodeString laterDate; - fDateFormat->format(toCalendar, laterDate, otherPos); - UnicodeString fallbackPattern; - fInfo->getFallbackIntervalPattern(fallbackPattern); - adjustPosition(fallbackPattern, earlierDate, pos, laterDate, otherPos, pos); - UnicodeString fallbackRange; - SimpleFormatter(fallbackPattern, 2, 2, status). - format(earlierDate, laterDate, fallbackRange, status); - if ( U_SUCCESS(status) && formatDatePlusTimeRange ) { - // fallbackRange has just the time range, need to format the date part and combine that - UnicodeString dateTimeFormatNoQuote(*fDateTimeFormat); - dateTimeFormatNoQuote.findAndReplace(UnicodeString(0x0027), UnicodeString()); - fDateFormat->applyPattern(*fDatePattern); - UnicodeString datePortion; - otherPos.setBeginIndex(0); - otherPos.setEndIndex(0); - fDateFormat->format(fromCalendar, datePortion, otherPos); - adjustPosition(dateTimeFormatNoQuote, fallbackRange, pos, datePortion, otherPos, pos); - const UnicodeString *values[2] = { - &fallbackRange, // {0} is time range - &datePortion, // {1} is single date portion - }; - SimpleFormatter(dateTimeFormatNoQuote, 2, 2, status). - formatAndReplace(values, 2, fallbackRange, NULL, 0, status); - } - if ( U_SUCCESS(status) ) { - appendTo.append(fallbackRange); - } - if (formatDatePlusTimeRange) { + + // {0} is time range + // {1} is single date portion + // TODO(ICU-20406): Use SimpleFormatter Iterator interface when available. + if (offsets[0] < offsets[1]) { + appendTo.append(patternBody.tempSubStringBetween(0, offsets[0])); + fDateFormat->applyPattern(*fTimePattern); + fDateFormat->setContext(fCapitalizationContext, status); + fallbackFormatRange(fromCalendar, toCalendar, appendTo, firstIndex, fphandler, status); + appendTo.append(patternBody.tempSubStringBetween(offsets[0], offsets[1])); + fDateFormat->applyPattern(*fDatePattern); + fDateFormat->_format(fromCalendar, appendTo, fphandler, status); + appendTo.append(patternBody.tempSubStringBetween(offsets[1])); + } else { + appendTo.append(patternBody.tempSubStringBetween(0, offsets[1])); + fDateFormat->applyPattern(*fDatePattern); + fDateFormat->setContext(fCapitalizationContext, status); + fDateFormat->_format(fromCalendar, appendTo, fphandler, status); + appendTo.append(patternBody.tempSubStringBetween(offsets[1], offsets[0])); + fDateFormat->applyPattern(*fTimePattern); + fDateFormat->setContext(UDISPCTX_CAPITALIZATION_NONE, status); + fallbackFormatRange(fromCalendar, toCalendar, appendTo, firstIndex, fphandler, status); + appendTo.append(patternBody.tempSubStringBetween(offsets[0])); + } + // restore full pattern fDateFormat->applyPattern(fullPattern); + } else { + fDateFormat->setContext(fCapitalizationContext, status); + fallbackFormatRange(fromCalendar, toCalendar, appendTo, firstIndex, fphandler, status); } return appendTo; } @@ -1615,6 +1758,7 @@ DateIntervalFormat::fgCalendarFieldToPatternLetter[] = }; + U_NAMESPACE_END #endif