status_t BTimeUnitFormat::Format(BString& buffer, const int32 value, const time_unit_element unit) const { if (unit < 0 || unit > B_TIME_UNIT_LAST) return B_BAD_VALUE; if (fFormatter == NULL) return B_NO_INIT; UErrorCode icuStatus = U_ZERO_ERROR; TimeUnitAmount* timeUnitAmount = new TimeUnitAmount((double)value, skUnitMap[unit], icuStatus); if (timeUnitAmount == NULL) return B_NO_MEMORY; if (!U_SUCCESS(icuStatus)) return B_ERROR; Formattable formattable; formattable.adoptObject(timeUnitAmount); FieldPosition pos(FieldPosition::DONT_CARE); UnicodeString unicodeResult; fFormatter->format(formattable, unicodeResult, pos, icuStatus); if (!U_SUCCESS(icuStatus)) return B_ERROR; BStringByteSink byteSink(&buffer); unicodeResult.toUTF8(byteSink); return B_OK; }
void TimeUnitTest::test10219Plurals() { Locale usLocale("en_US"); double values[2] = {1.588, 1.011}; UnicodeString expected[2][3] = { {"1 minute", "1.5 minutes", "1.58 minutes"}, {"1 minute", "1.0 minutes", "1.01 minutes"} }; UErrorCode status = U_ZERO_ERROR; TimeUnitFormat tuf(usLocale, status); if (U_FAILURE(status)) { dataerrln("generating TimeUnitFormat Object failed: %s", u_errorName(status)); return; } LocalPointer<DecimalFormat> nf((DecimalFormat *) NumberFormat::createInstance(usLocale, status)); if (U_FAILURE(status)) { dataerrln("generating NumberFormat Object failed: %s", u_errorName(status)); return; } for (int32_t j = 0; j < UPRV_LENGTHOF(values); ++j) { for (int32_t i = 0; i < UPRV_LENGTHOF(expected[j]); ++i) { nf->setMinimumFractionDigits(i); nf->setMaximumFractionDigits(i); nf->setRoundingMode(DecimalFormat::kRoundDown); tuf.setNumberFormat(*nf, status); if (U_FAILURE(status)) { dataerrln("setting NumberFormat failed: %s", u_errorName(status)); return; } UnicodeString actual; Formattable fmt; LocalPointer<TimeUnitAmount> tamt( new TimeUnitAmount(values[j], TimeUnit::UTIMEUNIT_MINUTE, status), status); if (U_FAILURE(status)) { dataerrln("generating TimeUnitAmount Object failed: %s", u_errorName(status)); return; } fmt.adoptObject(tamt.orphan()); tuf.format(fmt, actual, status); if (U_FAILURE(status)) { dataerrln("Actual formatting failed: %s", u_errorName(status)); return; } if (expected[j][i] != actual) { errln("Expected " + expected[j][i] + ", got " + actual); } } } // test parsing Formattable result; ParsePosition pos; UnicodeString formattedString = "1 minutes"; tuf.parseObject(formattedString, result, pos); if (formattedString.length() != pos.getIndex()) { errln("Expect parsing to go all the way to the end of the string."); } }
void CurrencyFormat::parseObject(const UnicodeString& source, Formattable& result, ParsePosition& pos) const { CurrencyAmount* currAmt = fmt->parseCurrency(source, pos); if (currAmt != NULL) { result.adoptObject(currAmt); } }
/** * Test basic */ void TimeUnitTest::testBasic() { const char* locales[] = {"en", "sl", "fr", "zh", "ar", "ru", "zh_Hant", "pa"}; for ( unsigned int locIndex = 0; locIndex < sizeof(locales)/sizeof(locales[0]); ++locIndex ) { UErrorCode status = U_ZERO_ERROR; Locale loc(locales[locIndex]); TimeUnitFormat** formats = new TimeUnitFormat*[2]; formats[UTMUTFMT_FULL_STYLE] = new TimeUnitFormat(loc, status); if (!assertSuccess("TimeUnitFormat(full)", status, TRUE)) return; formats[UTMUTFMT_ABBREVIATED_STYLE] = new TimeUnitFormat(loc, UTMUTFMT_ABBREVIATED_STYLE, status); if (!assertSuccess("TimeUnitFormat(short)", status)) return; #ifdef TUFMTTS_DEBUG std::cout << "locale: " << locales[locIndex] << "\n"; #endif for (int style = UTMUTFMT_FULL_STYLE; style <= UTMUTFMT_ABBREVIATED_STYLE; ++style) { for (TimeUnit::UTimeUnitFields j = TimeUnit::UTIMEUNIT_YEAR; j < TimeUnit::UTIMEUNIT_FIELD_COUNT; j = (TimeUnit::UTimeUnitFields)(j+1)) { #ifdef TUFMTTS_DEBUG std::cout << "time unit: " << j << "\n"; #endif double tests[] = {0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 5, 10, 100, 101.35}; for (unsigned int i = 0; i < sizeof(tests)/sizeof(tests[0]); ++i) { #ifdef TUFMTTS_DEBUG std::cout << "number: " << tests[i] << "\n"; #endif TimeUnitAmount* source = new TimeUnitAmount(tests[i], j, status); if (!assertSuccess("TimeUnitAmount()", status)) return; UnicodeString formatted; Formattable formattable; formattable.adoptObject(source); formatted = ((Format*)formats[style])->format(formattable, formatted, status); if (!assertSuccess("format()", status)) return; #ifdef TUFMTTS_DEBUG char formatResult[1000]; formatted.extract(0, formatted.length(), formatResult, "UTF-8"); std::cout << "format result: " << formatResult << "\n"; #endif Formattable result; ((Format*)formats[style])->parseObject(formatted, result, status); if (!assertSuccess("parseObject()", status)) return; if (result != formattable) { dataerrln("No round trip: "); } // other style parsing Formattable result_1; ((Format*)formats[1-style])->parseObject(formatted, result_1, status); if (!assertSuccess("parseObject()", status)) return; if (result_1 != formattable) { dataerrln("No round trip: "); } } } } delete formats[UTMUTFMT_FULL_STYLE]; delete formats[UTMUTFMT_ABBREVIATED_STYLE]; delete[] formats; } }
/* @bug 7902 * Tests for Greek Language. * This tests that requests for short unit names correctly fall back * to long unit names for a locale where the locale data does not * provide short unit names. As of CLDR 1.9, Greek is one such language. */ void TimeUnitTest::testGreekWithFallback() { UErrorCode status = U_ZERO_ERROR; const char* locales[] = {"el-GR", "el"}; TimeUnit::UTimeUnitFields tunits[] = {TimeUnit::UTIMEUNIT_SECOND, TimeUnit::UTIMEUNIT_MINUTE, TimeUnit::UTIMEUNIT_HOUR, TimeUnit::UTIMEUNIT_DAY, TimeUnit::UTIMEUNIT_MONTH, TimeUnit::UTIMEUNIT_YEAR}; UTimeUnitFormatStyle styles[] = {UTMUTFMT_FULL_STYLE, UTMUTFMT_ABBREVIATED_STYLE}; const int numbers[] = {1, 7}; const UChar oneSecond[] = {0x0031, 0x0020, 0x03b4, 0x03b5, 0x03c5, 0x03c4, 0x03b5, 0x03c1, 0x03cc, 0x03bb, 0x03b5, 0x03c0, 0x03c4, 0x03bf, 0}; const UChar oneSecondShort[] = {0x0031, 0x0020, 0x03b4, 0x03b5, 0x03c5, 0x03c4, 0x002e, 0}; const UChar oneMinute[] = {0x0031, 0x0020, 0x03bb, 0x03b5, 0x03c0, 0x03c4, 0x03cc, 0}; const UChar oneMinuteShort[] = {0x0031, 0x0020, 0x03bb, 0x03b5, 0x03c0, 0x002e, 0}; const UChar oneHour[] = {0x0031, 0x0020, 0x03ce, 0x03c1, 0x03b1, 0}; const UChar oneDay[] = {0x0031, 0x0020, 0x03b7, 0x03bc, 0x03ad, 0x03c1, 0x03b1, 0}; const UChar oneMonth[] = {0x0031, 0x0020, 0x03bc, 0x03ae, 0x03bd, 0x03b1, 0x03c2, 0}; const UChar oneMonthShort[] = {0x0031, 0x0020, 0x03bc, 0x03ae, 0x03bd, 0x002e, 0}; const UChar oneYear[] = {0x0031, 0x0020, 0x03ad, 0x03c4, 0x03bf, 0x03c2, 0}; const UChar sevenSeconds[] = {0x0037, 0x0020, 0x03b4, 0x03b5, 0x03c5, 0x03c4, 0x03b5, 0x03c1, 0x03cc, 0x03bb, 0x03b5, 0x03c0, 0x03c4, 0x03b1, 0}; const UChar sevenSecondsShort[] = {0x0037, 0x0020, 0x03b4, 0x03b5, 0x03c5, 0x03c4, 0x002e, 0}; const UChar sevenMinutes[] = {0x0037, 0x0020, 0x03bb, 0x03b5, 0x03c0, 0x03c4, 0x03ac, 0}; const UChar sevenMinutesShort[] = {0x0037, 0x0020, 0x03bb, 0x03b5, 0x03c0, 0x002e, 0}; const UChar sevenHours[] = {0x0037, 0x0020, 0x03ce, 0x03c1, 0x03b5, 0x03c2, 0}; const UChar sevenDays[] = {0x0037, 0x0020, 0x03b7, 0x03bc, 0x03ad, 0x03c1, 0x03b5, 0x03c2, 0}; const UChar sevenMonths[] = {0x0037, 0x0020, 0x03bc, 0x03ae, 0x03bd, 0x03b5, 0x3c2, 0}; const UChar sevenMonthsShort[] = {0x0037, 0x0020, 0x03bc, 0x03ae, 0x03bd, 0x002e, 0}; const UChar sevenYears[] = {0x0037, 0x0020, 0x03ad, 0x03c4, 0x03b7, 0}; const UnicodeString oneSecondStr(oneSecond); const UnicodeString oneSecondShortStr(oneSecondShort); const UnicodeString oneMinuteStr(oneMinute); const UnicodeString oneMinuteShortStr(oneMinuteShort); const UnicodeString oneHourStr(oneHour); const UnicodeString oneDayStr(oneDay); const UnicodeString oneMonthStr(oneMonth); const UnicodeString oneMonthShortStr(oneMonthShort); const UnicodeString oneYearStr(oneYear); const UnicodeString sevenSecondsStr(sevenSeconds); const UnicodeString sevenSecondsShortStr(sevenSecondsShort); const UnicodeString sevenMinutesStr(sevenMinutes); const UnicodeString sevenMinutesShortStr(sevenMinutesShort); const UnicodeString sevenHoursStr(sevenHours); const UnicodeString sevenDaysStr(sevenDays); const UnicodeString sevenMonthsStr(sevenMonths); const UnicodeString sevenMonthsShortStr(sevenMonthsShort); const UnicodeString sevenYearsStr(sevenYears); const UnicodeString expected[] = {oneSecondStr, oneMinuteStr, oneHourStr, oneDayStr, oneMonthStr, oneYearStr, oneSecondShortStr, oneMinuteShortStr, oneHourStr, oneDayStr, oneMonthShortStr, oneYearStr, sevenSecondsStr, sevenMinutesStr, sevenHoursStr, sevenDaysStr, sevenMonthsStr, sevenYearsStr, sevenSecondsShortStr, sevenMinutesShortStr, sevenHoursStr, sevenDaysStr, sevenMonthsShortStr, sevenYearsStr, oneSecondStr, oneMinuteStr, oneHourStr, oneDayStr, oneMonthStr, oneYearStr, oneSecondShortStr, oneMinuteShortStr, oneHourStr, oneDayStr, oneMonthShortStr, oneYearStr, sevenSecondsStr, sevenMinutesStr, sevenHoursStr, sevenDaysStr, sevenMonthsStr, sevenYearsStr, sevenSecondsShortStr, sevenMinutesShortStr, sevenHoursStr, sevenDaysStr, sevenMonthsShortStr, sevenYearsStr}; int counter = 0; for ( unsigned int locIndex = 0; locIndex < sizeof(locales)/sizeof(locales[0]); ++locIndex ) { Locale l = Locale::createFromName(locales[locIndex]); for ( unsigned int numberIndex = 0; numberIndex < sizeof(numbers)/sizeof(int); ++numberIndex ) { for ( unsigned int styleIndex = 0; styleIndex < sizeof(styles)/sizeof(styles[0]); ++styleIndex ) { for ( unsigned int unitIndex = 0; unitIndex < sizeof(tunits)/sizeof(tunits[0]); ++unitIndex ) { TimeUnitAmount *tamt = new TimeUnitAmount(numbers[numberIndex], tunits[unitIndex], status); if (U_FAILURE(status)) { dataerrln("generating TimeUnitAmount Object failed."); #ifdef TUFMTTS_DEBUG std::cout << "Failed to get TimeUnitAmount for " << tunits[unitIndex] << "\n"; #endif return; } TimeUnitFormat *tfmt = new TimeUnitFormat(l, styles[styleIndex], status); if (U_FAILURE(status)) { dataerrln("generating TimeUnitAmount Object failed."); #ifdef TUFMTTS_DEBUG std::cout << "Failed to get TimeUnitFormat for " << locales[locIndex] << "\n"; #endif return; } Formattable fmt; UnicodeString str; fmt.adoptObject(tamt); str = ((Format *)tfmt)->format(fmt, str, status); if (!assertSuccess("formatting relative time failed", status)) { delete tfmt; #ifdef TUFMTTS_DEBUG std::cout << "Failed to format" << "\n"; #endif return; } #ifdef TUFMTTS_DEBUG char tmp[128]; //output char tmp1[128]; //expected int len = 0; u_strToUTF8(tmp, 128, &len, str.getTerminatedBuffer(), str.length(), &status); u_strToUTF8(tmp1, 128, &len, expected[counter].unescape().getTerminatedBuffer(), expected[counter].unescape().length(), &status); std::cout << "Formatted string : " << tmp << " expected : " << tmp1 << "\n"; #endif if (!assertEquals("formatted time string is not expected, locale: " + UnicodeString(locales[locIndex]) + " style: " + (int)styles[styleIndex] + " units: " + (int)tunits[unitIndex], expected[counter], str)) { delete tfmt; str.remove(); return; } delete tfmt; str.remove(); ++counter; } } } } }
void TimeUnitFormat::parseObject(const UnicodeString& source, Formattable& result, ParsePosition& pos) const { Formattable resultNumber(0.0); UBool withNumberFormat = false; TimeUnit::UTimeUnitFields resultTimeUnit = TimeUnit::UTIMEUNIT_FIELD_COUNT; int32_t oldPos = pos.getIndex(); int32_t newPos = -1; int32_t longestParseDistance = 0; UnicodeString* countOfLongestMatch = NULL; #ifdef TMUTFMT_DEBUG char res[1000]; source.extract(0, source.length(), res, "UTF-8"); std::cout << "parse source: " << res << "\n"; #endif // parse by iterating through all available patterns // and looking for the longest match. for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR; i < TimeUnit::UTIMEUNIT_FIELD_COUNT; i = (TimeUnit::UTimeUnitFields)(i+1)) { Hashtable* countToPatterns = fTimeUnitToCountToPatterns[i]; int32_t elemPos = UHASH_FIRST; const UHashElement* elem = NULL; while ((elem = countToPatterns->nextElement(elemPos)) != NULL){ const UHashTok keyTok = elem->key; UnicodeString* count = (UnicodeString*)keyTok.pointer; #ifdef TMUTFMT_DEBUG count->extract(0, count->length(), res, "UTF-8"); std::cout << "parse plural count: " << res << "\n"; #endif const UHashTok valueTok = elem->value; // the value is a pair of MessageFormat* MessageFormat** patterns = (MessageFormat**)valueTok.pointer; for (UTimeUnitFormatStyle style = UTMUTFMT_FULL_STYLE; style < UTMUTFMT_FORMAT_STYLE_COUNT; style = (UTimeUnitFormatStyle)(style + 1)) { MessageFormat* pattern = patterns[style]; pos.setErrorIndex(-1); pos.setIndex(oldPos); // see if we can parse Formattable parsed; pattern->parseObject(source, parsed, pos); if (pos.getErrorIndex() != -1 || pos.getIndex() == oldPos) { continue; } #ifdef TMUTFMT_DEBUG std::cout << "parsed.getType: " << parsed.getType() << "\n"; #endif Formattable tmpNumber(0.0); if (pattern->getArgTypeCount() != 0) { Formattable& temp = parsed[0]; if (temp.getType() == Formattable::kString) { UnicodeString tmpString; UErrorCode pStatus = U_ZERO_ERROR; getNumberFormat().parse(temp.getString(tmpString), tmpNumber, pStatus); if (U_FAILURE(pStatus)) { continue; } } else if (temp.isNumeric()) { tmpNumber = temp; } else { continue; } } int32_t parseDistance = pos.getIndex() - oldPos; if (parseDistance > longestParseDistance) { if (pattern->getArgTypeCount() != 0) { resultNumber = tmpNumber; withNumberFormat = true; } else { withNumberFormat = false; } resultTimeUnit = i; newPos = pos.getIndex(); longestParseDistance = parseDistance; countOfLongestMatch = count; } } } } /* After find the longest match, parse the number. * Result number could be null for the pattern without number pattern. * such as unit pattern in Arabic. * When result number is null, use plural rule to set the number. */ if (withNumberFormat == false && longestParseDistance != 0) { // set the number using plurrual count if (0 == countOfLongestMatch->compare(PLURAL_COUNT_ZERO, 4)) { resultNumber = Formattable(0.0); } else if (0 == countOfLongestMatch->compare(PLURAL_COUNT_ONE, 3)) { resultNumber = Formattable(1.0); } else if (0 == countOfLongestMatch->compare(PLURAL_COUNT_TWO, 3)) { resultNumber = Formattable(2.0); } else { // should not happen. // TODO: how to handle? resultNumber = Formattable(3.0); } } if (longestParseDistance == 0) { pos.setIndex(oldPos); pos.setErrorIndex(0); } else { UErrorCode status = U_ZERO_ERROR; TimeUnitAmount* tmutamt = new TimeUnitAmount(resultNumber, resultTimeUnit, status); if (U_SUCCESS(status)) { result.adoptObject(tmutamt); pos.setIndex(newPos); pos.setErrorIndex(-1); } else { pos.setIndex(oldPos); pos.setErrorIndex(0); } } }
void TimeUnitFormat::parseObject(const UnicodeString& source, Formattable& result, ParsePosition& pos) const { double resultNumber = -1; UBool withNumberFormat = false; TimeUnit::UTimeUnitFields resultTimeUnit = TimeUnit::UTIMEUNIT_FIELD_COUNT; int32_t oldPos = pos.getIndex(); int32_t newPos = -1; int32_t longestParseDistance = 0; UnicodeString* countOfLongestMatch = NULL; #ifdef TMUTFMT_DEBUG char res[1000]; source.extract(0, source.length(), res, "UTF-8"); std::cout << "parse source: " << res << "\n"; #endif // parse by iterating through all available patterns // and looking for the longest match. for (TimeUnit::UTimeUnitFields i = TimeUnit::UTIMEUNIT_YEAR; i < TimeUnit::UTIMEUNIT_FIELD_COUNT; i = (TimeUnit::UTimeUnitFields)(i+1)) { Hashtable* countToPatterns = fTimeUnitToCountToPatterns[i]; int32_t elemPos = -1; const UHashElement* elem = NULL; while ((elem = countToPatterns->nextElement(elemPos)) != NULL){ const UHashTok keyTok = elem->key; UnicodeString* count = (UnicodeString*)keyTok.pointer; #ifdef TMUTFMT_DEBUG count->extract(0, count->length(), res, "UTF-8"); std::cout << "parse plural count: " << res << "\n"; #endif const UHashTok valueTok = elem->value; // the value is a pair of MessageFormat* MessageFormat** patterns = (MessageFormat**)valueTok.pointer; for (EStyle style = kFull; style < kTotal; style = (EStyle)(style + 1)) { MessageFormat* pattern = patterns[style]; pos.setErrorIndex(-1); pos.setIndex(oldPos); // see if we can parse Formattable parsed; pattern->parseObject(source, parsed, pos); if (pos.getErrorIndex() != -1 || pos.getIndex() == oldPos) { continue; } #ifdef TMUTFMT_DEBUG std::cout << "parsed.getType: " << parsed.getType() << "\n"; #endif double tmpNumber = 0; if (pattern->getArgTypeCount() != 0) { // pattern with Number as beginning, such as "{0} d". // check to make sure that the timeUnit is consistent Formattable& temp = parsed[0]; if (temp.getType() == Formattable::kDouble) { tmpNumber = temp.getDouble(); } else if (temp.getType() == Formattable::kLong) { tmpNumber = temp.getLong(); } else { continue; } UnicodeString select = fPluralRules->select(tmpNumber); #ifdef TMUTFMT_DEBUG select.extract(0, select.length(), res, "UTF-8"); std::cout << "parse plural select count: " << res << "\n"; #endif if (*count != select) { continue; } } int32_t parseDistance = pos.getIndex() - oldPos; if (parseDistance > longestParseDistance) { if (pattern->getArgTypeCount() != 0) { resultNumber = tmpNumber; withNumberFormat = true; } else { withNumberFormat = false; } resultTimeUnit = i; newPos = pos.getIndex(); longestParseDistance = parseDistance; countOfLongestMatch = count; } } } } /* After find the longest match, parse the number. * Result number could be null for the pattern without number pattern. * such as unit pattern in Arabic. * When result number is null, use plural rule to set the number. */ if (withNumberFormat == false && longestParseDistance != 0) { // set the number using plurrual count if ( *countOfLongestMatch == PLURAL_COUNT_ZERO ) { resultNumber = 0; } else if ( *countOfLongestMatch == PLURAL_COUNT_ONE ) { resultNumber = 1; } else if ( *countOfLongestMatch == PLURAL_COUNT_TWO ) { resultNumber = 2; } else { // should not happen. // TODO: how to handle? resultNumber = 3; } } if (longestParseDistance == 0) { pos.setIndex(oldPos); pos.setErrorIndex(0); } else { UErrorCode status = U_ZERO_ERROR; TimeUnitAmount* tmutamt = new TimeUnitAmount(resultNumber, resultTimeUnit, status); if (U_SUCCESS(status)) { result.adoptObject(tmutamt); pos.setIndex(newPos); pos.setErrorIndex(-1); } else { pos.setIndex(oldPos); pos.setErrorIndex(0); } } }