// This is a pattern-of-last-resort used when we can't load a usable pattern out // of a resource. staticconst char16_t gDefaultPattern[] =
{
0x79, 0x4D, 0x4D, 0x64, 0x64, 0x20, 0x68, 0x68, 0x3A, 0x6D, 0x6D, 0x20, 0x61, 0
}; /* "yMMdd hh:mm a" */
// This prefix is designed to NEVER MATCH real text, in order to // suppress the parsing of negative numbers. Adjust as needed (if // this becomes valid Unicode). staticconst char16_t SUPPRESS_NEGATIVE_PREFIX[] = {0xAB00, 0};
/** * These are the tags we expect to see in normal resource bundle files associated * with a locale.
*/ staticconst char16_t QUOTE = 0x27; // Single quote
/* * The field range check bias for each UDateFormatField. * The bias is added to the minimum and maximum values * before they are compared to the parsed number. * For example, the calendar stores zero-based month numbers * but the parsed month numbers start at 1, so the bias is 1. * * A value of -1 means that the value is not checked.
*/ staticconst int32_t gFieldRangeBias[] = {
-1, // 'G' - UDAT_ERA_FIELD
-1, // 'y' - UDAT_YEAR_FIELD
1, // 'M' - UDAT_MONTH_FIELD
0, // 'd' - UDAT_DATE_FIELD
-1, // 'k' - UDAT_HOUR_OF_DAY1_FIELD
-1, // 'H' - UDAT_HOUR_OF_DAY0_FIELD
0, // 'm' - UDAT_MINUTE_FIELD
0, // 's' - UDAT_SECOND_FIELD
-1, // 'S' - UDAT_FRACTIONAL_SECOND_FIELD (0-999?)
-1, // 'E' - UDAT_DAY_OF_WEEK_FIELD (1-7?)
-1, // 'D' - UDAT_DAY_OF_YEAR_FIELD (1 - 366?)
-1, // 'F' - UDAT_DAY_OF_WEEK_IN_MONTH_FIELD (1-5?)
-1, // 'w' - UDAT_WEEK_OF_YEAR_FIELD (1-52?)
-1, // 'W' - UDAT_WEEK_OF_MONTH_FIELD (1-5?)
-1, // 'a' - UDAT_AM_PM_FIELD
-1, // 'h' - UDAT_HOUR1_FIELD
-1, // 'K' - UDAT_HOUR0_FIELD
-1, // 'z' - UDAT_TIMEZONE_FIELD
-1, // 'Y' - UDAT_YEAR_WOY_FIELD
-1, // 'e' - UDAT_DOW_LOCAL_FIELD
-1, // 'u' - UDAT_EXTENDED_YEAR_FIELD
-1, // 'g' - UDAT_JULIAN_DAY_FIELD
-1, // 'A' - UDAT_MILLISECONDS_IN_DAY_FIELD
-1, // 'Z' - UDAT_TIMEZONE_RFC_FIELD
-1, // 'v' - UDAT_TIMEZONE_GENERIC_FIELD
0, // 'c' - UDAT_STANDALONE_DAY_FIELD
1, // 'L' - UDAT_STANDALONE_MONTH_FIELD
-1, // 'Q' - UDAT_QUARTER_FIELD (1-4?)
-1, // 'q' - UDAT_STANDALONE_QUARTER_FIELD
-1, // 'V' - UDAT_TIMEZONE_SPECIAL_FIELD
-1, // 'U' - UDAT_YEAR_NAME_FIELD
-1, // 'O' - UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD
-1, // 'X' - UDAT_TIMEZONE_ISO_FIELD
-1, // 'x' - UDAT_TIMEZONE_ISO_LOCAL_FIELD
-1, // 'r' - UDAT_RELATED_YEAR_FIELD #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
-1, // ':' - UDAT_TIME_SEPARATOR_FIELD #else
-1, // (no pattern character currently) - UDAT_TIME_SEPARATOR_FIELD #endif
};
// When calendar uses hebr numbering (i.e. he@calendar=hebrew), // offset the years within the current millennium down to 1-999 staticconst int32_t HEBREW_CAL_CUR_MILLENIUM_START_YEAR = 5000; staticconst int32_t HEBREW_CAL_CUR_MILLENIUM_END_YEAR = 6000;
/** * Maximum range for detecting daylight offset of a time zone when parsed time zone * string indicates it's daylight saving time, but the detected time zone does not * observe daylight saving time at the parsed date.
*/ staticconstdouble MAX_DAYLIGHT_DETECTION_RANGE = 30*365*24*60*60*1000.0;
// no matter what the locale's default number format looked like, we want // to modify it so that it doesn't use thousands separators, doesn't always // show the decimal point, and recognizes integers only when parsing staticvoid fixNumberFormatForDates(NumberFormat &nf) {
nf.setGroupingUsed(false);
DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(&nf); if (decfmt != nullptr) {
decfmt->setDecimalSeparatorAlwaysShown(false);
}
nf.setParseIntegerOnly(true);
nf.setMinimumFractionDigits(0); // To prevent "Jan 1.00, 1997.00"
}
/** * Not for public consumption; used by DateFormat. This constructor * never fails. If the resource data is not available, it uses the * the last resort symbols.
*/
SimpleDateFormat::SimpleDateFormat(const Locale& locale,
UErrorCode& status)
: fPattern(gDefaultPattern),
fLocale(locale)
{ if (U_FAILURE(status)) return;
initializeBooleanAttributes();
initializeCalendar(nullptr, fLocale, status);
fSymbols = DateFormatSymbols::createForLocale(fLocale, status); if (U_FAILURE(status))
{
status = U_ZERO_ERROR; delete fSymbols; // This constructor doesn't fail; it uses last resort data
fSymbols = new DateFormatSymbols(status); /* test for nullptr */ if (fSymbols == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR; return;
}
}
// fSimpleNumberFormatter references fNumberFormatter, delete it // before we call the = operator which may invalidate fNumberFormatter delete fSimpleNumberFormatter;
fSimpleNumberFormatter = nullptr;
// TimeZoneFormat can now be set independently via setter. // If it is nullptr, it will be lazily initialized from locale. delete fTimeZoneFormat;
fTimeZoneFormat = nullptr;
TimeZoneFormat *otherTZFormat;
{ // Synchronization is required here, when accessing other.fTimeZoneFormat, // because another thread may be concurrently executing other.tzFormat(), // a logically const function that lazily creates other.fTimeZoneFormat. // // Without synchronization, reordered memory writes could allow us // to see a non-null fTimeZoneFormat before the object itself was // fully initialized. In case of a race, it doesn't matter whether // we see a null or a fully initialized other.fTimeZoneFormat, // only that we avoid seeing a partially initialized object. // // Once initialized, no const function can modify fTimeZoneFormat, // meaning that once we have safely grabbed the other.fTimeZoneFormat // pointer, continued synchronization is not required to use it.
Mutex m(&LOCK);
otherTZFormat = other.fTimeZoneFormat;
} if (otherTZFormat) {
fTimeZoneFormat = new TimeZoneFormat(*otherTZFormat);
}
if (fSharedNumberFormatters != nullptr) {
freeSharedNumberFormatters(fSharedNumberFormatters);
fSharedNumberFormatters = nullptr;
} if (other.fSharedNumberFormatters != nullptr) {
fSharedNumberFormatters = allocSharedNumberFormatters(); if (fSharedNumberFormatters) { for (int32_t i = 0; i < UDAT_FIELD_COUNT; ++i) {
SharedObject::copyPtr(
other.fSharedNumberFormatters[i],
fSharedNumberFormatters[i]);
}
}
}
UErrorCode localStatus = U_ZERO_ERROR; // SimpleNumberFormatter does not have a copy constructor. Furthermore, // it references data from an internal field, fNumberFormatter, // so we must rematerialize that reference after copying over the number formatter.
initSimpleNumberFormatter(localStatus); return *this;
}
void SimpleDateFormat::construct(EStyle timeStyle,
EStyle dateStyle, const Locale& locale,
UErrorCode& status)
{ // called by several constructors to load pattern data from the resources if (U_FAILURE(status)) return;
// We will need the calendar to know what type of symbols to load.
initializeCalendar(nullptr, locale, status); if (U_FAILURE(status)) return;
// Load date time patterns directly from resources. constchar* cType = fCalendar ? fCalendar->getType() : nullptr;
LocalUResourceBundlePointer bundle(ures_open(nullptr, locale.getBaseName(), &status)); if (U_FAILURE(status)) return;
// Check for "gregorian" fallback. if (cTypeIsGregorian || status == U_MISSING_RESOURCE_ERROR) {
status = U_ZERO_ERROR;
dateTimePatterns.adoptInstead(
ures_getByKeyWithFallback(bundle.getAlias(), "calendar/gregorian/DateTimePatterns",
(UResourceBundle*)nullptr, &status));
} if (U_FAILURE(status)) return;
LocalUResourceBundlePointer currentBundle;
if (ures_getSize(dateTimePatterns.getAlias()) <= kDateTime)
{
status = U_INVALID_FORMAT_ERROR; return;
}
// create a symbols object from the locale
fSymbols = DateFormatSymbols::createForLocale(locale, status); if (U_FAILURE(status)) return; /* test for nullptr */ if (fSymbols == nullptr) {
status = U_MEMORY_ALLOCATION_ERROR; return;
}
UnicodeString timePattern; if (timeStyle >= kFull && timeStyle <= kShort) { bool hasRgOrHcSubtag = false; // also use DTPG if the locale has the "rg" or "hc" ("hours") subtag-- even if the overriding region // or hour cycle is the same as the one we get by default, we go through the DateTimePatternGenerator
UErrorCode dummyErr1 = U_ZERO_ERROR, dummyErr2 = U_ZERO_ERROR; if (locale.getKeywordValue("rg", nullptr, 0, dummyErr1) > 0 || locale.getKeywordValue("hours", nullptr, 0, dummyErr2) > 0) {
hasRgOrHcSubtag = true;
}
constchar* baseLocID = locale.getBaseName(); if (baseLocID != nullptr && uprv_strcmp(baseLocID,"und")!=0) {
UErrorCode useStatus = U_ZERO_ERROR;
Locale baseLoc(baseLocID);
Locale validLoc(getLocale(ULOC_VALID_LOCALE, useStatus)); if (hasRgOrHcSubtag || (U_SUCCESS(useStatus) && validLoc!=baseLoc)) { bool useDTPG = hasRgOrHcSubtag; constchar* baseReg = baseLoc.getCountry(); // empty string if no region if ((baseReg != nullptr && baseReg[0] != 0 &&
uprv_strncmp(baseReg,validLoc.getCountry(),ULOC_COUNTRY_CAPACITY)!=0)
|| uprv_strncmp(baseLoc.getLanguage(),validLoc.getLanguage(),ULOC_LANG_CAPACITY)!=0) { // use DTPG if // * baseLoc has a region and validLoc does not have the same one (or has none), OR // * validLoc has a different language code than baseLoc // * the original locale has the rg or hc subtag
useDTPG = true;
} if (useDTPG) { // The standard time formats may have the wrong time cycle, because: // the valid locale differs in important ways (region, language) from // the base locale. // We could *also* check whether they do actually have a mismatch with // the time cycle preferences for the region, but that is a lot more // work for little or no additional benefit, since just going ahead // and always synthesizing the time format as per the following should // create a locale-appropriate pattern with cycle that matches the // region preferences anyway.
LocalPointer<DateTimePatternGenerator> dtpg(DateTimePatternGenerator::createInstanceNoStdPat(locale, useStatus)); if (U_SUCCESS(useStatus)) {
UnicodeString timeSkeleton(true, timeSkeletons[timeStyle], -1);
timePattern = dtpg->getBestPattern(timeSkeleton, useStatus);
}
}
}
}
}
// if the pattern should include both date and time information, use the date/time // pattern string as a guide to tell use how to glue together the appropriate date // and time pattern strings. if ((timeStyle != kNone) && (dateStyle != kNone))
{
UnicodeString tempus1(timePattern); if (tempus1.length() == 0) {
currentBundle.adoptInstead(
ures_getByIndex(dateTimePatterns.getAlias(), static_cast<int32_t>(timeStyle), nullptr, &status)); if (U_FAILURE(status)) {
status = U_INVALID_FORMAT_ERROR; return;
} switch (ures_getType(currentBundle.getAlias())) { case URES_STRING: {
resStr = ures_getString(currentBundle.getAlias(), &resStrLen, &status); break;
} case URES_ARRAY: {
resStr = ures_getStringByIndex(currentBundle.getAlias(), 0, &resStrLen, &status);
ovrStr = ures_getStringByIndex(currentBundle.getAlias(), 1, &ovrStrLen, &status);
fTimeOverride.setTo(true, ovrStr, ovrStrLen); break;
} default: {
status = U_INVALID_FORMAT_ERROR; return;
}
}
void
SimpleDateFormat::initialize(const Locale& locale,
UErrorCode& status)
{ if (U_FAILURE(status)) return;
parsePattern(); // Need this before initNumberFormatters(), to set fHasHanYearChar
// Simple-minded hack to force Gannen year numbering for ja@calendar=japanese // if format is non-numeric (includes 年) and fDateOverride is not already specified. // Now this does get updated if applyPattern subsequently changes the pattern type. if (fDateOverride.isBogus() && fHasHanYearChar &&
fCalendar != nullptr && uprv_strcmp(fCalendar->getType(),"japanese") == 0 &&
uprv_strcmp(fLocale.getLanguage(),"ja") == 0) {
fDateOverride.setTo(u"y=jpanyear", -1);
}
// We don't need to check that the row count is >= 1, since all 2d arrays have at // least one row
fNumberFormat = NumberFormat::createInstance(locale, status); if (fNumberFormat != nullptr && U_SUCCESS(status))
{
fixNumberFormatForDates(*fNumberFormat); //fNumberFormat->setLenient(true); // Java uses a custom DateNumberFormat to format/parse
} elseif (U_SUCCESS(status))
{
status = U_MISSING_RESOURCE_ERROR;
}
}
/* Initialize the fields we use to disambiguate ambiguous years. Separate * so we can call it from readObject().
*/ void SimpleDateFormat::initializeDefaultCentury()
{ if(fCalendar) {
fHaveDefaultCentury = fCalendar->haveDefaultCentury(); if(fHaveDefaultCentury) {
fDefaultCenturyStart = fCalendar->defaultCenturyStart();
fDefaultCenturyStartYear = fCalendar->defaultCenturyStartYear();
} else {
fDefaultCenturyStart = DBL_MIN;
fDefaultCenturyStartYear = -1;
}
}
}
/* * Initialize the boolean attributes. Separate so we can call it from all constructors.
*/ void SimpleDateFormat::initializeBooleanAttributes()
{
UErrorCode status = U_ZERO_ERROR;
/* Define one-century window into which to disambiguate dates using * two-digit years. Make public in JDK 1.2.
*/ void SimpleDateFormat::parseAmbiguousDatesAsAfter(UDate startDate, UErrorCode& status)
{ if(U_FAILURE(status)) { return;
} if(!fCalendar) {
status = U_ILLEGAL_ARGUMENT_ERROR; return;
}
UnicodeString&
SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo,
FieldPositionHandler& handler, UErrorCode& status) const
{ if ( U_FAILURE(status) ) { return appendTo;
}
Calendar* workCal = &cal;
Calendar* calClone = nullptr; if (&cal != fCalendar && uprv_strcmp(cal.getType(), fCalendar->getType()) != 0) { // Different calendar type // We use the time and time zone from the input calendar, but // do not use the input calendar for field calculation.
calClone = fCalendar->clone(); if (calClone != nullptr) {
UDate t = cal.getTime(status);
calClone->setTime(t, status);
calClone->setTimeZone(cal.getTimeZone());
workCal = calClone;
} else {
status = U_MEMORY_ALLOCATION_ERROR; return appendTo;
}
}
// loop through the pattern string character by character
int32_t patternLength = fPattern.length(); for (int32_t i = 0; i < patternLength && U_SUCCESS(status); ++i) {
char16_t ch = fPattern[i];
// Use subFormat() to format a repeated pattern character // when a different pattern or non-pattern character is seen if (ch != prevCh && count > 0) {
subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++,
prevCh, handler, *workCal, status);
count = 0;
} if (ch == QUOTE) { // Consecutive single quotes are a single quote literal, // either outside of quotes or between quotes if ((i+1) < patternLength && fPattern[i+1] == QUOTE) {
appendTo += QUOTE;
++i;
} else {
inQuote = ! inQuote;
}
} elseif (!inQuote && isSyntaxChar(ch)) { // ch is a date-time pattern character to be interpreted // by subFormat(); count the number of times it is repeated
prevCh = ch;
++count;
} else { // Append quoted characters and unquoted non-pattern characters
appendTo += ch;
}
}
// Format the last item in the pattern, if any if (count > 0) {
subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++,
prevCh, handler, *workCal, status);
}
/* Map calendar field into calendar field level. * the larger the level, the smaller the field unit. * For example, UCAL_ERA level is 0, UCAL_YEAR level is 10, * UCAL_MONTH level is 20. * NOTE: if new fields adds in, the table needs to update.
*/ const int32_t
SimpleDateFormat::fgCalendarFieldToLevel[] =
{ /*GyM*/ 0, 10, 20, /*wW*/ 20, 30, /*dDEF*/ 30, 20, 30, 30, /*ahHm*/ 40, 50, 50, 60, /*sS*/ 70, 80, /*z?Y*/ 0, 0, 10, /*eug*/ 30, 10, 0, /*A?.*/ 40, 0, 0
};
int32_t SimpleDateFormat::getLevelFromChar(char16_t ch) { // Map date field LETTER into calendar field level. // the larger the level, the smaller the field unit. // NOTE: if new fields adds in, the table needs to update. staticconst int32_t mapCharToLevel[] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, //
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // ! " # $ % & ' ( ) * + , - . /
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR // 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, #else // 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, #endif // @ A B C D E F G H I J K L M N O
-1, 40, -1, -1, 20, 30, 30, 0, 50, -1, -1, 50, 20, 20, -1, 0, // P Q R S T U V W X Y Z [ \ ] ^ _
-1, 20, -1, 80, -1, 10, 0, 30, 0, 10, 0, -1, -1, -1, -1, -1, // ` a b c d e f g h i j k l m n o
-1, 40, -1, 30, 30, 30, -1, 0, 50, -1, -1, 50, 0, 60, -1, -1, // p q r s t u v w x y z { | } ~
-1, 20, 10, 70, -1, 10, 0, 20, 0, 10, 0, -1, -1, -1, -1, -1
};
/** * Append symbols[value] to dst. Make sure the array index is not out * of bounds.
*/ staticinlinevoid
_appendSymbol(UnicodeString& dst,
int32_t value, const UnicodeString* symbols,
int32_t symbolsCount) {
U_ASSERT(0 <= value && value < symbolsCount); if (0 <= value && value < symbolsCount) {
dst += symbols[value];
}
}
staticinlinevoid
_appendSymbolWithMonthPattern(UnicodeString& dst, int32_t value, const UnicodeString* symbols, int32_t symbolsCount, const UnicodeString* monthPattern, UErrorCode& status) {
U_ASSERT(0 <= value && value < symbolsCount); if (0 <= value && value < symbolsCount) { if (monthPattern == nullptr) {
dst += symbols[value];
} else {
SimpleFormatter(*monthPattern, 1, 1, status).format(symbols[value], dst, status);
}
}
}
while (moreToProcess) {
int32_t delimiterPosition = str.indexOf(static_cast<char16_t>(ULOC_KEYWORD_ITEM_SEPARATOR_UNICODE), start); if (delimiterPosition == -1) {
moreToProcess = false;
len = str.length() - start;
} else {
len = delimiterPosition - start;
}
UnicodeString currentString(str,start,len);
int32_t equalSignPosition = currentString.indexOf(static_cast<char16_t>(ULOC_KEYWORD_ASSIGN_UNICODE), 0); if (equalSignPosition == -1) { // Simple override string such as "hebrew"
nsName.setTo(currentString);
ovrField.setToBogus();
} else { // Field specific override string such as "y=hebrew"
nsName.setTo(currentString,equalSignPosition+1);
ovrField.setTo(currentString,0,1); // We just need the first character.
}
int32_t nsNameHash = nsName.hashCode(); // See if the numbering system is in the override list, if not, then add it.
NSOverride *curr = overrideList; const SharedNumberFormat *snf = nullptr;
UBool found = false; while ( curr && !found ) { if ( curr->hash == nsNameHash ) {
snf = curr->snf;
found = true;
}
curr = curr->next;
}
if (!found) {
LocalPointer<NSOverride> cur(new NSOverride); if (!cur.isNull()) { char kw[ULOC_KEYWORD_AND_VALUES_CAPACITY];
uprv_strcpy(kw,"numbers=");
nsName.extract(0,len,kw+8,ULOC_KEYWORD_AND_VALUES_CAPACITY-8,US_INV);
// Now that we have an appropriate number formatter, fill in the appropriate spaces in the // number formatters table. if (ovrField.isBogus()) { switch (type) { case kOvrStrDate: case kOvrStrBoth: { for ( int8_t i=0 ; i<kDateFieldsCount; i++ ) {
SharedObject::copyPtr(snf, fSharedNumberFormatters[kDateFields[i]]);
} if (type==kOvrStrDate) { break;
}
U_FALLTHROUGH;
} case kOvrStrTime : { for ( int8_t i=0 ; i<kTimeFieldsCount; i++ ) {
SharedObject::copyPtr(snf, fSharedNumberFormatters[kTimeFields[i]]);
} break;
}
}
} else { // if the pattern character is unrecognized, signal an error and bail out
UDateFormatField patternCharIndex =
DateFormatSymbols::getPatternCharIndex(ovrField.charAt(0)); if (patternCharIndex == UDAT_FIELD_COUNT) {
status = U_INVALID_FORMAT_ERROR; if (overrideList) {
overrideList->free();
} return;
}
SharedObject::copyPtr(snf, fSharedNumberFormatters[patternCharIndex]);
}
// if the pattern character is unrecognized, signal an error and dump out if (patternCharIndex == UDAT_FIELD_COUNT)
{ if (ch != 0x6C) { // pattern char 'l' (SMALL LETTER L) just gets ignored
status = U_INVALID_FORMAT_ERROR;
} return;
}
UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex];
int32_t value = 0; // Don't get value unless it is useful if (field < UCAL_FIELD_COUNT) {
value = (patternCharIndex != UDAT_RELATED_YEAR_FIELD)? cal.get(field, status): cal.getRelatedYear(status); if (U_FAILURE(status)) { return;
}
}
const NumberFormat *currentNumberFormat = getNumberFormatByIndex(patternCharIndex); if (currentNumberFormat == nullptr) {
status = U_INTERNAL_PROGRAM_ERROR; return;
}
switch (patternCharIndex) {
// for any "G" symbol, write out the appropriate era string // "GGGG" is wide era name, "GGGGG" is narrow era name, anything else is abbreviated name case UDAT_ERA_FIELD:
{ constauto* calType = cal.getType(); if (uprv_strcmp(calType,"chinese") == 0 || uprv_strcmp(calType,"dangi") == 0) {
zeroPaddingNumber(currentNumberFormat,appendTo, value, 1, 9); // as in ICU4J
} else { if (count == 5) {
_appendSymbol(appendTo, value, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount);
capContextUsageType = DateFormatSymbols::kCapContextUsageEraNarrow;
} elseif (count == 4) {
_appendSymbol(appendTo, value, fSymbols->fEraNames, fSymbols->fEraNamesCount);
capContextUsageType = DateFormatSymbols::kCapContextUsageEraWide;
} else {
_appendSymbol(appendTo, value, fSymbols->fEras, fSymbols->fErasCount);
capContextUsageType = DateFormatSymbols::kCapContextUsageEraAbbrev;
}
}
} break;
case UDAT_YEAR_NAME_FIELD: if (fSymbols->fShortYearNames != nullptr && value <= fSymbols->fShortYearNamesCount) { // the Calendar YEAR field runs 1 through 60 for cyclic years
_appendSymbol(appendTo, value - 1, fSymbols->fShortYearNames, fSymbols->fShortYearNamesCount); break;
} // else fall through to numeric year handling, do not break here
U_FALLTHROUGH;
// OLD: for "yyyy", write out the whole year; for "yy", write out the last 2 digits // NEW: UTS#35: //Year y yy yyy yyyy yyyyy //AD 1 1 01 001 0001 00001 //AD 12 12 12 012 0012 00012 //AD 123 123 23 123 0123 00123 //AD 1234 1234 34 1234 1234 01234 //AD 12345 12345 45 12345 12345 12345 case UDAT_YEAR_FIELD: case UDAT_YEAR_WOY_FIELD: if (fDateOverride.compare(hebr)==0 && value>HEBREW_CAL_CUR_MILLENIUM_START_YEAR && value<HEBREW_CAL_CUR_MILLENIUM_END_YEAR) {
value-=HEBREW_CAL_CUR_MILLENIUM_START_YEAR;
} if(count == 2)
zeroPaddingNumber(currentNumberFormat, appendTo, value, 2, 2); else
zeroPaddingNumber(currentNumberFormat, appendTo, value, count, maxIntCount); break;
// for "MMMM"/"LLLL", write out the whole month name, for "MMM"/"LLL", write out the month // abbreviation, for "M"/"L" or "MM"/"LL", write out the month as a number with the // appropriate number of digits // for "MMMMM"/"LLLLL", use the narrow form case UDAT_MONTH_FIELD: case UDAT_STANDALONE_MONTH_FIELD: if (uprv_strcmp(cal.getType(),"hebrew") == 0) { if (HebrewCalendar::isLeapYear(cal.get(UCAL_YEAR,status)) && value == 6 && count >= 3 )
value = 13; // Show alternate form for Adar II in leap years in Hebrew calendar. if (!HebrewCalendar::isLeapYear(cal.get(UCAL_YEAR,status)) && value >= 6 && count < 3 )
value--; // Adjust the month number down 1 in Hebrew non-leap years, i.e. Adar is 6, not 7.
}
{
int32_t isLeapMonth = (fSymbols->fLeapMonthPatterns != nullptr && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount)?
cal.get(UCAL_IS_LEAP_MONTH, status): 0; // should consolidate the next section by using arrays of pointers & counts for the right symbols... if (count == 5) { if (patternCharIndex == UDAT_MONTH_FIELD) {
_appendSymbolWithMonthPattern(appendTo, value, fSymbols->fNarrowMonths, fSymbols->fNarrowMonthsCount,
(isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatNarrow]): nullptr, status);
} else {
_appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneNarrowMonths, fSymbols->fStandaloneNarrowMonthsCount,
(isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneNarrow]): nullptr, status);
}
capContextUsageType = DateFormatSymbols::kCapContextUsageMonthNarrow;
} elseif (count == 4) { if (patternCharIndex == UDAT_MONTH_FIELD) {
_appendSymbolWithMonthPattern(appendTo, value, fSymbols->fMonths, fSymbols->fMonthsCount,
(isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatWide]): nullptr, status);
capContextUsageType = DateFormatSymbols::kCapContextUsageMonthFormat;
} else {
_appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneMonths, fSymbols->fStandaloneMonthsCount,
(isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneWide]): nullptr, status);
capContextUsageType = DateFormatSymbols::kCapContextUsageMonthStandalone;
}
} elseif (count == 3) { if (patternCharIndex == UDAT_MONTH_FIELD) {
_appendSymbolWithMonthPattern(appendTo, value, fSymbols->fShortMonths, fSymbols->fShortMonthsCount,
(isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatAbbrev]): nullptr, status);
capContextUsageType = DateFormatSymbols::kCapContextUsageMonthFormat;
} else {
_appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneShortMonths, fSymbols->fStandaloneShortMonthsCount,
(isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneAbbrev]): nullptr, status);
capContextUsageType = DateFormatSymbols::kCapContextUsageMonthStandalone;
}
} else {
UnicodeString monthNumber;
zeroPaddingNumber(currentNumberFormat,monthNumber, value + 1, count, maxIntCount);
_appendSymbolWithMonthPattern(appendTo, 0, &monthNumber, 1,
(isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternNumeric]): nullptr, status);
}
} break;
// for "k" and "kk", write out the hour, adjusting midnight to appear as "24" case UDAT_HOUR_OF_DAY1_FIELD: if (value == 0)
zeroPaddingNumber(currentNumberFormat,appendTo, cal.getMaximum(UCAL_HOUR_OF_DAY) + 1, count, maxIntCount); else
zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount); break;
// for "ee" or "e", use local numeric day-of-the-week // for "EEEEEE" or "eeeeee", write out the short day-of-the-week name // for "EEEEE" or "eeeee", write out the narrow day-of-the-week name // for "EEEE" or "eeee", write out the wide day-of-the-week name // for "EEE" or "EE" or "E" or "eee", write out the abbreviated day-of-the-week name case UDAT_DOW_LOCAL_FIELD: if ( count < 3 ) {
zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount); break;
} // fall through to EEEEE-EEE handling, but for that we don't want local day-of-week, // we want standard day-of-week, so first fix value to work for EEEEE-EEE.
value = cal.get(UCAL_DAY_OF_WEEK, status); if (U_FAILURE(status)) { return;
} // fall through, do not break here
U_FALLTHROUGH; case UDAT_DAY_OF_WEEK_FIELD: if (count == 5) {
_appendSymbol(appendTo, value, fSymbols->fNarrowWeekdays,
fSymbols->fNarrowWeekdaysCount);
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.24 Sekunden
(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.