#if U_CHARSET_FAMILY==U_EBCDIC_FAMILY /** * If we are on EBCDIC, use an iterator which will * traverse the bundles in ASCII order.
*/ #define U_USE_ASCII_BUNDLE_ITERATOR #define U_SORT_ASCII_BUNDLE_ITERATOR #endif
// ***************************************************************************** // class DateTimePatternGenerator // ***************************************************************************** staticconst char16_t Canonical_Items[] = { // GyQMwWEDFdaHmsSv
CAP_G, LOW_Y, CAP_Q, CAP_M, LOW_W, CAP_W, CAP_E,
CAP_D, CAP_F, LOW_D, LOW_A, // The UDATPG_x_FIELD constants and these fields have a different order than in ICU4J
CAP_H, LOW_M, LOW_S, CAP_S, LOW_V, 0
};
{LOW_A, UDATPG_DAYPERIOD_FIELD, DT_SHORT, 1, 3},
{LOW_A, UDATPG_DAYPERIOD_FIELD, DT_LONG, 4, 0},
{LOW_A, UDATPG_DAYPERIOD_FIELD, DT_NARROW, 5, 0},
{LOW_B, UDATPG_DAYPERIOD_FIELD, DT_SHORT - DT_DELTA, 1, 3},
{LOW_B, UDATPG_DAYPERIOD_FIELD, DT_LONG - DT_DELTA, 4, 0},
{LOW_B, UDATPG_DAYPERIOD_FIELD, DT_NARROW - DT_DELTA, 5, 0}, // b needs to be closer to a than to B, so we make this 3*DT_DELTA
{CAP_B, UDATPG_DAYPERIOD_FIELD, DT_SHORT - 3*DT_DELTA, 1, 3},
{CAP_B, UDATPG_DAYPERIOD_FIELD, DT_LONG - 3*DT_DELTA, 4, 0},
{CAP_B, UDATPG_DAYPERIOD_FIELD, DT_NARROW - 3*DT_DELTA, 5, 0},
{CAP_H, UDATPG_HOUR_FIELD, DT_NUMERIC + 10*DT_DELTA, 1, 2}, // 24 hour
{LOW_K, UDATPG_HOUR_FIELD, DT_NUMERIC + 11*DT_DELTA, 1, 2}, // 24 hour
{LOW_H, UDATPG_HOUR_FIELD, DT_NUMERIC, 1, 2}, // 12 hour
{CAP_K, UDATPG_HOUR_FIELD, DT_NUMERIC + DT_DELTA, 1, 2}, // 12 hour // The C code has had versions of the following 3, keep & update. Should not need these, but... // Without these, certain tests using e.g. staticGetSkeleton fail because j/J in patterns // get skipped instead of mapped to the right hour chars, for example in // DateFormatTest::TestPatternFromSkeleton // IntlTestDateTimePatternGeneratorAPI:: testStaticGetSkeleton // DateIntervalFormatTest::testTicket11985 // Need to investigate better handling of jJC replacement e.g. in staticGetSkeleton.
{CAP_J, UDATPG_HOUR_FIELD, DT_NUMERIC + 5*DT_DELTA, 1, 2}, // 12/24 hour no AM/PM
{LOW_J, UDATPG_HOUR_FIELD, DT_NUMERIC + 6*DT_DELTA, 1, 6}, // 12/24 hour
{CAP_C, UDATPG_HOUR_FIELD, DT_NUMERIC + 7*DT_DELTA, 1, 6}, // 12/24 hour with preferred dayPeriods for 12
{0, UDATPG_FIELD_COUNT, 0, 0, 0} , // last row of dtTypes[]
};
staticconstchar* const CLDR_FIELD_APPEND[] = { "Era", "Year", "Quarter", "Month", "Week", "*", "Day-Of-Week", "*", "*", "Day", "DayPeriod", // The UDATPG_x_FIELD constants and these fields have a different order than in ICU4J "Hour", "Minute", "Second", "FractionalSecond", "Timezone"
};
staticconstchar* const CLDR_FIELD_NAME[UDATPG_FIELD_COUNT] = { "era", "year", "quarter", "month", "week", "weekOfMonth", "weekday", "dayOfYear", "weekdayOfMonth", "day", "dayperiod", // The UDATPG_x_FIELD constants and these fields have a different order than in ICU4J "hour", "minute", "second", "fractionalSecond", "zone"
};
// Value deleter for hashmap.
U_CFUNC void U_CALLCONV deleteAllowedHourFormats(void *ptr) {
uprv_free(ptr);
}
// Close hashmap at cleanup.
U_CFUNC UBool U_CALLCONV allowedHourFormatsCleanup() {
uhash_close(localeToAllowedHourFormatsMap); returntrue;
}
enum AllowedHourFormat{
ALLOWED_HOUR_FORMAT_UNKNOWN = -1,
ALLOWED_HOUR_FORMAT_h,
ALLOWED_HOUR_FORMAT_H,
ALLOWED_HOUR_FORMAT_K, // Added ICU-20383, used by JP
ALLOWED_HOUR_FORMAT_k, // Added ICU-20383, not currently used
ALLOWED_HOUR_FORMAT_hb,
ALLOWED_HOUR_FORMAT_hB,
ALLOWED_HOUR_FORMAT_Kb, // Added ICU-20383, not currently used
ALLOWED_HOUR_FORMAT_KB, // Added ICU-20383, not currently used // ICU-20383 The following are unlikely and not currently used
ALLOWED_HOUR_FORMAT_Hb,
ALLOWED_HOUR_FORMAT_HB
};
} // namespace
void
DateTimePatternGenerator::initData(const Locale& locale, UErrorCode &status, UBool skipStdPatterns) { //const char *baseLangName = locale.getBaseName(); // unused if (U_FAILURE(status)) { return; } if (locale.isBogus()) {
status = U_ILLEGAL_ARGUMENT_ERROR; return;
}
skipMatcher = nullptr;
fAvailableFormatKeyHash=nullptr;
addCanonicalItems(status); if (!skipStdPatterns) { // skip to prevent circular dependency when called from SimpleDateFormat::construct
addICUPatterns(locale, status);
}
addCLDRData(locale, status);
setDateTimeFromCalendar(locale, status);
setDecimalSymbols(locale, status);
umtx_initOnce(initOnce, loadAllowedHourFormatsData, status);
getAllowedHourFormats(locale, status); // If any of the above methods failed then the object is in an invalid state.
internalErrorCode = status;
} // DateTimePatternGenerator::initData
LocalUResourceBundlePointer rb(ures_openDirect(nullptr, "supplementalData", &status)); if (U_FAILURE(status)) { return; }
AllowedHourFormatsSink sink; // TODO: Currently in the enumeration each table allocates a new array. // Try to reduce the number of memory allocations. Consider storing a // UVector32 with the concatenation of all of the sub-arrays, put the start index // into the hashmap, store 6 single-value sub-arrays right at the beginning of the // vector (at index enum*2) for easy data sharing, copy sub-arrays into runtime // object. Remember to clean up the vector, too.
ures_getAllItemsWithFallback(rb.getAlias(), "timeData", sink, status);
}
Locale maxLocale; // must be here for correct lifetime if (*language == '\0' || *country == '\0') {
maxLocale = locale;
UErrorCode localStatus = U_ZERO_ERROR;
maxLocale.addLikelySubtags(localStatus); if (U_SUCCESS(localStatus)) {
language = maxLocale.getLanguage();
country = maxLocale.getCountry();
}
} if (*language == '\0') { // Unexpected, but fail gracefully
language = "und";
} if (*country == '\0') {
country = "001";
}
// We need to check if there is an hour cycle on locale char buffer[8];
int32_t count = locale.getKeywordValue("hours", buffer, sizeof(buffer), status);
// Check if the region has an alias if (allowedFormats == nullptr) {
UErrorCode localStatus = U_ZERO_ERROR; const Region* region = Region::getInstance(country, localStatus); if (U_SUCCESS(localStatus)) {
country = region->getRegionCode(); // the real region code
allowedFormats = getAllowedHourFormatsLangCountry(language, country, status);
}
}
if (allowedFormats != nullptr) { // Lookup is successful // Here allowedFormats points to a list consisting of key for preferredFormat, // followed by one or more keys for allowedFormats, then followed by ALLOWED_HOUR_FORMAT_UNKNOWN. if (!fDefaultHourFormatChar) { switch (allowedFormats[0]) { case ALLOWED_HOUR_FORMAT_h: fDefaultHourFormatChar = LOW_H; break; case ALLOWED_HOUR_FORMAT_H: fDefaultHourFormatChar = CAP_H; break; case ALLOWED_HOUR_FORMAT_K: fDefaultHourFormatChar = CAP_K; break; case ALLOWED_HOUR_FORMAT_k: fDefaultHourFormatChar = LOW_K; break; default: fDefaultHourFormatChar = CAP_H; break;
}
}
for (int32_t i = 0; i < UPRV_LENGTHOF(fAllowedHourFormats); ++i) {
fAllowedHourFormats[i] = allowedFormats[i + 1]; if (fAllowedHourFormats[i] == ALLOWED_HOUR_FORMAT_UNKNOWN) { break;
}
}
} else { // Lookup failed, twice if (!fDefaultHourFormatChar) {
fDefaultHourFormatChar = CAP_H;
}
fAllowedHourFormats[0] = ALLOWED_HOUR_FORMAT_H;
fAllowedHourFormats[1] = ALLOWED_HOUR_FORMAT_UNKNOWN;
}
}
UDateFormatHourCycle
DateTimePatternGenerator::getDefaultHourCycle(UErrorCode& status) const { if (U_FAILURE(status)) { return UDAT_HOUR_CYCLE_23;
} if (fDefaultHourFormatChar == 0) { // We need to return something, but the caller should ignore it // anyways since the returned status is a failure.
status = U_UNSUPPORTED_ERROR; return UDAT_HOUR_CYCLE_23;
} switch (fDefaultHourFormatChar) { case CAP_K: return UDAT_HOUR_CYCLE_11; case LOW_H: return UDAT_HOUR_CYCLE_12; case CAP_H: return UDAT_HOUR_CYCLE_23; case LOW_K: return UDAT_HOUR_CYCLE_24; default:
UPRV_UNREACHABLE_EXIT;
}
}
LocalUResourceBundlePointer rb(ures_open(nullptr, locale.getBaseName(), &status));
CharString calendarTypeToUse; // to be filled in with the type to use, if all goes well
getCalendarTypeToUse(locale, calendarTypeToUse, status);
// HACK to get around the fact that the old SimpleDateFormat code (actually, Calendar::getCalendarTypeForLocale() ) // returns "gregorian" for ja_JP_TRADITIONAL instead of "japanese" if (uprv_strcmp(locale.getBaseName(), "ja_JP_TRADITIONAL") == 0) {
calendarTypeToUse.clear().append("gregorian", status);
}
void
DateTimePatternGenerator::getCalendarTypeToUse(const Locale& locale, CharString& destination, UErrorCode& err) {
destination.clear().append(DT_DateTimeGregorianTag, -1, err); // initial default if ( U_SUCCESS(err) ) {
UErrorCode localStatus = U_ZERO_ERROR; char localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY]; // obtain a locale that always has the calendar key value that should be used
ures_getFunctionalEquivalent(
localeWithCalendarKey,
ULOC_LOCALE_IDENTIFIER_CAPACITY,
nullptr, "calendar", "calendar",
locale.getName(),
nullptr, false,
&localStatus);
localeWithCalendarKey[ULOC_LOCALE_IDENTIFIER_CAPACITY-1] = 0; // ensure null termination // now get the calendar key value from that locale // (the call to ures_getFunctionalEquivalent() above might fail, and if it does, localeWithCalendarKey // won't contain a `calendar` keyword. If this happens, the line below will stomp on `destination`, // so we have to check the return code before overwriting `destination`.) if (U_SUCCESS(localStatus)) {
destination = ulocimp_getKeywordValue(localeWithCalendarKey, "calendar", localStatus);
} // If the input locale was invalid, don't fail with missing resource error, instead // continue with default of Gregorian. if (U_FAILURE(localStatus) && localStatus != U_MISSING_RESOURCE_ERROR) {
err = localStatus;
}
}
}
void
DateTimePatternGenerator::consumeShortTimePattern(const UnicodeString& shortTimePattern,
UErrorCode& status) { if (U_FAILURE(status)) { return; } // ICU-20383 No longer set fDefaultHourFormatChar to the hour format character from // this pattern; instead it is set from localeToAllowedHourFormatsMap which now // includes entries for both preferred and allowed formats.
// HACK for hh:ss
hackTimes(shortTimePattern, status);
}
struct DateTimePatternGenerator::AppendItemFormatsSink : public ResourceSink {
// Destination for data, modified via setters.
DateTimePatternGenerator& dtpg;
virtualvoid put(constchar *key, ResourceValue &value, UBool /*isRoot*/,
UErrorCode &errorCode) override { const UnicodeString formatKey(key, -1, US_INV); if (!dtpg.isAvailableFormatSet(formatKey) ) {
dtpg.setAvailableFormat(formatKey, errorCode); // Add pattern with its associated skeleton. Override any duplicate // derived from std patterns, but not a previous availableFormats entry: const UnicodeString& formatValue = value.getUnicodeString(errorCode);
conflictingPattern.remove();
dtpg.addPatternWithSkeleton(formatValue, &formatKey, true, conflictingPattern, errorCode);
}
}
};
// Virtual destructors must be defined out of line.
DateTimePatternGenerator::AppendItemFormatsSink::~AppendItemFormatsSink() {}
DateTimePatternGenerator::AppendItemNamesSink::~AppendItemNamesSink() {}
DateTimePatternGenerator::AvailableFormatsSink::~AvailableFormatsSink() {}
LocalUResourceBundlePointer rb(ures_open(nullptr, locale.getName(), &errorCode)); if (U_FAILURE(errorCode)) { return; }
CharString calendarTypeToUse; // to be filled in with the type to use, if all goes well
getCalendarTypeToUse(locale, calendarTypeToUse, errorCode); if (U_FAILURE(errorCode)) { return; }
// Local err to ignore resource not found exceptions
UErrorCode err = U_ZERO_ERROR;
void
DateTimePatternGenerator::getAppendName(UDateTimePatternField field, UnicodeString& value) {
value = SINGLE_QUOTE;
value += fieldDisplayNames[field][UDATPG_WIDTH_APPENDITEM];
value += SINGLE_QUOTE;
}
void
DateTimePatternGenerator::setDateTimeFormat(UDateFormatStyle style, const UnicodeString& dtFormat, UErrorCode& status) { if (U_FAILURE(status)) { return;
} if (style < UDAT_FULL || style > UDAT_SHORT) {
status = U_ILLEGAL_ARGUMENT_ERROR; return;
}
dateTimeFormat[style] = dtFormat; // Note for the following: getTerminatedBuffer() can re-allocate the UnicodeString // buffer so we do this here before clients request a const ref to the UnicodeString // or its buffer.
dateTimeFormat[style].getTerminatedBuffer(); // NUL-terminate for the C API.
}
// For DateTimePatternGenerator::addPatternWithSkeleton - // If skeletonToUse is specified, then an availableFormats entry is being added. In this case: // 1. We pass that skeleton to matcher.set instead of having it derive a skeleton from the pattern. // 2. If the new entry's skeleton or basePattern does match an existing entry but that entry also had a skeleton specified // (i.e. it was also from availableFormats), then the new entry does not override it regardless of the value of the override // parameter. This prevents later availableFormats entries from a parent locale overriding earlier ones from the actual // specified locale. However, availableFormats entries *should* override entries with matching skeleton whose skeleton was // derived (i.e. entries derived from the standard date/time patters for the specified locale). // 3. When adding the pattern (patternMap->add), we set a new boolean to indicate that the added entry had a // specified skeleton (which sets a new field in the PtnElem in the PatternMap).
UDateTimePatternConflict
DateTimePatternGenerator::addPatternWithSkeleton( const UnicodeString& pattern, const UnicodeString* skeletonToUse,
UBool override,
UnicodeString& conflictingPattern,
UErrorCode& status)
{ if (U_FAILURE(internalErrorCode)) {
status = internalErrorCode; return UDATPG_NO_CONFLICT;
}
DateTimeMatcher matcher; if ( skeletonToUse == nullptr ) {
matcher.set(pattern, fp, skeleton);
matcher.getBasePattern(basePattern);
} else {
matcher.set(*skeletonToUse, fp, skeleton); // no longer trims skeleton fields to max len 3, per #7930
matcher.getBasePattern(basePattern); // or perhaps instead: basePattern = *skeletonToUse;
} // We only care about base conflicts - and replacing the pattern associated with a base - if: // 1. the conflicting previous base pattern did *not* have an explicit skeleton; in that case the previous // base + pattern combination was derived from either (a) a canonical item, (b) a standard format, or // (c) a pattern specified programmatically with a previous call to addPattern (which would only happen // if we are getting here from a subsequent call to addPattern). // 2. a skeleton is specified for the current pattern, but override=false; in that case we are checking // availableFormats items from root, which should not override any previous entry with the same base.
UBool entryHadSpecifiedSkeleton; const UnicodeString *duplicatePattern = patternMap->getPatternFromBasePattern(basePattern, entryHadSpecifiedSkeleton); if (duplicatePattern != nullptr && (!entryHadSpecifiedSkeleton || (skeletonToUse != nullptr && !override))) {
conflictingStatus = UDATPG_BASE_CONFLICT;
conflictingPattern = *duplicatePattern; if (!override) { return conflictingStatus;
}
} // The only time we get here with override=true and skeletonToUse!=null is when adding availableFormats // items from CLDR data. In that case, we don't want an item from a parent locale to replace an item with // same skeleton from the specified locale, so skip the current item if skeletonWasSpecified is true for // the previously-specified conflicting item. const PtnSkeleton* entrySpecifiedSkeleton = nullptr;
duplicatePattern = patternMap->getPatternFromSkeleton(skeleton, &entrySpecifiedSkeleton); if (duplicatePattern != nullptr ) {
conflictingStatus = UDATPG_CONFLICT;
conflictingPattern = *duplicatePattern; if (!override || (skeletonToUse != nullptr && entrySpecifiedSkeleton != nullptr)) { return conflictingStatus;
}
}
patternMap->add(basePattern, skeleton, pattern, skeletonToUse != nullptr, status); if(U_FAILURE(status)) { return conflictingStatus;
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.23Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.