UBool TimeZone::parseCustomID(const UnicodeString& id, int32_t& sign, int32_t& hour, int32_t& min, int32_t& sec) { static const int32_t kParseFailed = -99999; NumberFormat* numberFormat = 0; UnicodeString idUppercase = id; idUppercase.toUpper(); if (id.length() > GMT_ID_LENGTH && idUppercase.startsWith(GMT_ID)) { ParsePosition pos(GMT_ID_LENGTH); sign = 1; hour = 0; min = 0; sec = 0; if (id[pos.getIndex()] == MINUS /*'-'*/) { sign = -1; } else if (id[pos.getIndex()] != PLUS /*'+'*/) { return FALSE; } pos.setIndex(pos.getIndex() + 1); UErrorCode success = U_ZERO_ERROR; numberFormat = NumberFormat::createInstance(success); if(U_FAILURE(success)){ return FALSE; } numberFormat->setParseIntegerOnly(TRUE); // Look for either hh:mm, hhmm, or hh int32_t start = pos.getIndex(); Formattable n(kParseFailed); numberFormat->parse(id, n, pos); if (pos.getIndex() == start) { delete numberFormat; return FALSE; } hour = n.getLong(); if (pos.getIndex() < id.length()) { if (pos.getIndex() - start > 2 || id[pos.getIndex()] != COLON) { delete numberFormat; return FALSE; } // hh:mm pos.setIndex(pos.getIndex() + 1); int32_t oldPos = pos.getIndex(); n.setLong(kParseFailed); numberFormat->parse(id, n, pos); if ((pos.getIndex() - oldPos) != 2) { // must be 2 digits delete numberFormat; return FALSE; } min = n.getLong(); if (pos.getIndex() < id.length()) { if (id[pos.getIndex()] != COLON) { delete numberFormat; return FALSE; } // [:ss] pos.setIndex(pos.getIndex() + 1); oldPos = pos.getIndex(); n.setLong(kParseFailed); numberFormat->parse(id, n, pos); if (pos.getIndex() != id.length() || (pos.getIndex() - oldPos) != 2) { delete numberFormat; return FALSE; } sec = n.getLong(); } } else { // Supported formats are below - // // HHmmss // Hmmss // HHmm // Hmm // HH // H int32_t length = pos.getIndex() - start; if (length <= 0 || 6 < length) { // invalid length delete numberFormat; return FALSE; } switch (length) { case 1: case 2: // already set to hour break; case 3: case 4: min = hour % 100; hour /= 100; break; case 5: case 6: sec = hour % 100; min = (hour/100) % 100; hour /= 10000; break; } } delete numberFormat; if (hour > kMAX_CUSTOM_HOUR || min > kMAX_CUSTOM_MIN || sec > kMAX_CUSTOM_SEC) { return FALSE; } return TRUE; } return FALSE; }
/** * This test does round-trip testing (format -> parse -> format -> parse -> etc.) of * NumberFormat. */ void IntlTestNumberFormatAPI::testAPI(/* char* par */) { UErrorCode status = U_ZERO_ERROR; // ======= Test constructors logln("Testing NumberFormat constructors"); NumberFormat *def = NumberFormat::createInstance(status); if(U_FAILURE(status)) { errln("ERROR: Could not create NumberFormat (default)"); } status = U_ZERO_ERROR; NumberFormat *fr = NumberFormat::createInstance(Locale::getFrench(), status); if(U_FAILURE(status)) { errln("ERROR: Could not create NumberFormat (French)"); } NumberFormat *cur = NumberFormat::createCurrencyInstance(status); if(U_FAILURE(status)) { errln("ERROR: Could not create NumberFormat (currency, default)"); } status = U_ZERO_ERROR; NumberFormat *cur_fr = NumberFormat::createCurrencyInstance(Locale::getFrench(), status); if(U_FAILURE(status)) { errln("ERROR: Could not create NumberFormat (currency, French)"); } NumberFormat *per = NumberFormat::createPercentInstance(status); if(U_FAILURE(status)) { errln("ERROR: Could not create NumberFormat (percent, default)"); } status = U_ZERO_ERROR; NumberFormat *per_fr = NumberFormat::createPercentInstance(Locale::getFrench(), status); if(U_FAILURE(status)) { errln("ERROR: Could not create NumberFormat (percent, French)"); } // ======= Test equality if (per_fr != NULL && cur_fr != NULL) { logln("Testing equality operator"); if( *per_fr == *cur_fr || ! ( *per_fr != *cur_fr) ) { errln("ERROR: == failed"); } } // ======= Test various format() methods if (cur_fr != NULL) { logln("Testing various format() methods"); double d = -10456.0037; int32_t l = 100000000; Formattable fD(d); Formattable fL(l); UnicodeString res1, res2, res3, res4, res5, res6; FieldPosition pos1(0), pos2(0), pos3(0), pos4(0); res1 = cur_fr->format(d, res1); logln( (UnicodeString) "" + (int32_t) d + " formatted to " + res1); res2 = cur_fr->format(l, res2); logln((UnicodeString) "" + (int32_t) l + " formatted to " + res2); res3 = cur_fr->format(d, res3, pos1); logln( (UnicodeString) "" + (int32_t) d + " formatted to " + res3); res4 = cur_fr->format(l, res4, pos2); logln((UnicodeString) "" + (int32_t) l + " formatted to " + res4); status = U_ZERO_ERROR; res5 = cur_fr->format(fD, res5, pos3, status); if(U_FAILURE(status)) { errln("ERROR: format(Formattable [double]) failed"); } logln((UnicodeString) "" + (int32_t) fD.getDouble() + " formatted to " + res5); status = U_ZERO_ERROR; res6 = cur_fr->format(fL, res6, pos4, status); if(U_FAILURE(status)) { errln("ERROR: format(Formattable [long]) failed"); } logln((UnicodeString) "" + fL.getLong() + " formatted to " + res6); } // ======= Test parse() if (fr != NULL) { logln("Testing parse()"); double d = -10456.0037; UnicodeString text("-10,456.0037"); Formattable result1, result2, result3; ParsePosition pos(0), pos01(0); fr->parseObject(text, result1, pos); if(result1.getType() != Formattable::kDouble && result1.getDouble() != d) { errln("ERROR: Roundtrip failed (via parse()) for " + text); } logln(text + " parsed into " + (int32_t) result1.getDouble()); fr->parse(text, result2, pos01); if(result2.getType() != Formattable::kDouble && result2.getDouble() != d) { errln("ERROR: Roundtrip failed (via parse()) for " + text); } logln(text + " parsed into " + (int32_t) result2.getDouble()); status = U_ZERO_ERROR; fr->parse(text, result3, status); if(U_FAILURE(status)) { errln("ERROR: parse() failed"); } if(result3.getType() != Formattable::kDouble && result3.getDouble() != d) { errln("ERROR: Roundtrip failed (via parse()) for " + text); } logln(text + " parsed into " + (int32_t) result3.getDouble()); } // ======= Test getters and setters if (fr != NULL && def != NULL) { logln("Testing getters and setters"); int32_t count = 0; const Locale *locales = NumberFormat::getAvailableLocales(count); logln((UnicodeString) "Got " + count + " locales" ); for(int32_t i = 0; i < count; i++) { UnicodeString name(locales[i].getName(),""); logln(name); } fr->setParseIntegerOnly( def->isParseIntegerOnly() ); if(fr->isParseIntegerOnly() != def->isParseIntegerOnly() ) { errln("ERROR: setParseIntegerOnly() failed"); } fr->setGroupingUsed( def->isGroupingUsed() ); if(fr->isGroupingUsed() != def->isGroupingUsed() ) { errln("ERROR: setGroupingUsed() failed"); } fr->setMaximumIntegerDigits( def->getMaximumIntegerDigits() ); if(fr->getMaximumIntegerDigits() != def->getMaximumIntegerDigits() ) { errln("ERROR: setMaximumIntegerDigits() failed"); } fr->setMinimumIntegerDigits( def->getMinimumIntegerDigits() ); if(fr->getMinimumIntegerDigits() != def->getMinimumIntegerDigits() ) { errln("ERROR: setMinimumIntegerDigits() failed"); } fr->setMaximumFractionDigits( def->getMaximumFractionDigits() ); if(fr->getMaximumFractionDigits() != def->getMaximumFractionDigits() ) { errln("ERROR: setMaximumFractionDigits() failed"); } fr->setMinimumFractionDigits( def->getMinimumFractionDigits() ); if(fr->getMinimumFractionDigits() != def->getMinimumFractionDigits() ) { errln("ERROR: setMinimumFractionDigits() failed"); } } // ======= Test getStaticClassID() logln("Testing getStaticClassID()"); status = U_ZERO_ERROR; NumberFormat *test = new DecimalFormat(status); if(U_FAILURE(status)) { errln("ERROR: Couldn't create a NumberFormat"); } if(test->getDynamicClassID() != DecimalFormat::getStaticClassID()) { errln("ERROR: getDynamicClassID() didn't return the expected value"); } delete test; delete def; delete fr; delete cur; delete cur_fr; delete per; delete per_fr; }
/** * Parse a custom time zone identifier and return a corresponding zone. * @param id a string of the form GMT[+-]hh:mm, GMT[+-]hhmm, or * GMT[+-]hh. * @return a newly created SimpleTimeZone with the given offset and * no Daylight Savings Time, or null if the id cannot be parsed. */ TimeZone* TimeZone::createCustomTimeZone(const UnicodeString& id) { static const int32_t kParseFailed = -99999; NumberFormat* numberFormat = 0; UnicodeString idUppercase = id; idUppercase.toUpper(); if (id.length() > GMT_ID_LENGTH && idUppercase.startsWith(GMT_ID)) { ParsePosition pos(GMT_ID_LENGTH); UBool negative = FALSE; int32_t offset; if (id[pos.getIndex()] == 0x002D /*'-'*/) negative = TRUE; else if (id[pos.getIndex()] != 0x002B /*'+'*/) return 0; pos.setIndex(pos.getIndex() + 1); UErrorCode success = U_ZERO_ERROR; numberFormat = NumberFormat::createInstance(success); numberFormat->setParseIntegerOnly(TRUE); // Look for either hh:mm, hhmm, or hh int32_t start = pos.getIndex(); Formattable n(kParseFailed); numberFormat->parse(id, n, pos); if (pos.getIndex() == start) { delete numberFormat; return 0; } offset = n.getLong(); if (pos.getIndex() < id.length() && id[pos.getIndex()] == 0x003A /*':'*/) { // hh:mm offset *= 60; pos.setIndex(pos.getIndex() + 1); int32_t oldPos = pos.getIndex(); n.setLong(kParseFailed); numberFormat->parse(id, n, pos); if (pos.getIndex() == oldPos) { delete numberFormat; return 0; } offset += n.getLong(); } else { // hhmm or hh // Be strict about interpreting something as hh; it must be // an offset < 30, and it must be one or two digits. Thus // 0010 is interpreted as 00:10, but 10 is interpreted as // 10:00. if (offset < 30 && (pos.getIndex() - start) <= 2) offset *= 60; // hh, from 00 to 29; 30 is 00:30 else offset = offset % 100 + offset / 100 * 60; // hhmm } if(negative) offset = -offset; delete numberFormat; return new SimpleTimeZone(offset * 60000, CUSTOM_ID); } return 0; }