Home | History | Annotate | Download | only in i18n
      1 //  2016 and later: Unicode, Inc. and others.
      2 // License & terms of use: http://www.unicode.org/copyright.html
      3 /*
      4 *******************************************************************************
      5 * Copyright (C) 1997-2016, International Business Machines Corporation and    *
      6 * others. All Rights Reserved.                                                *
      7 *******************************************************************************
      8 *
      9 * File SMPDTFMT.CPP
     10 *
     11 * Modification History:
     12 *
     13 *   Date        Name        Description
     14 *   02/19/97    aliu        Converted from java.
     15 *   03/31/97    aliu        Modified extensively to work with 50 locales.
     16 *   04/01/97    aliu        Added support for centuries.
     17 *   07/09/97    helena      Made ParsePosition into a class.
     18 *   07/21/98    stephen     Added initializeDefaultCentury.
     19 *                             Removed getZoneIndex (added in DateFormatSymbols)
     20 *                             Removed subParseLong
     21 *                             Removed chk
     22 *   02/22/99    stephen     Removed character literals for EBCDIC safety
     23 *   10/14/99    aliu        Updated 2-digit year parsing so that only "00" thru
     24 *                           "99" are recognized. {j28 4182066}
     25 *   11/15/99    weiv        Added support for week of year/day of week format
     26 ********************************************************************************
     27 */
     28 
     29 #define ZID_KEY_MAX 128
     30 
     31 #include "unicode/utypes.h"
     32 
     33 #if !UCONFIG_NO_FORMATTING
     34 #include "unicode/smpdtfmt.h"
     35 #include "unicode/dtfmtsym.h"
     36 #include "unicode/ures.h"
     37 #include "unicode/msgfmt.h"
     38 #include "unicode/calendar.h"
     39 #include "unicode/gregocal.h"
     40 #include "unicode/timezone.h"
     41 #include "unicode/decimfmt.h"
     42 #include "unicode/dcfmtsym.h"
     43 #include "unicode/uchar.h"
     44 #include "unicode/uniset.h"
     45 #include "unicode/ustring.h"
     46 #include "unicode/basictz.h"
     47 #include "unicode/simpleformatter.h"
     48 #include "unicode/simpletz.h"
     49 #include "unicode/rbtz.h"
     50 #include "unicode/tzfmt.h"
     51 #include "unicode/ucasemap.h"
     52 #include "unicode/utf16.h"
     53 #include "unicode/vtzone.h"
     54 #include "unicode/udisplaycontext.h"
     55 #include "unicode/brkiter.h"
     56 #include "uresimp.h"
     57 #include "olsontz.h"
     58 #include "patternprops.h"
     59 #include "fphdlimp.h"
     60 #include "hebrwcal.h"
     61 #include "cstring.h"
     62 #include "uassert.h"
     63 #include "cmemory.h"
     64 #include "umutex.h"
     65 #include <float.h>
     66 #include "smpdtfst.h"
     67 #include "sharednumberformat.h"
     68 #include "ucasemap_imp.h"
     69 #include "ustr_imp.h"
     70 #include "charstr.h"
     71 #include "uvector.h"
     72 #include "cstr.h"
     73 #include "dayperiodrules.h"
     74 #include "tznames_impl.h"   // ZONE_NAME_U16_MAX
     75 
     76 #if defined( U_DEBUG_CALSVC ) || defined (U_DEBUG_CAL)
     77 #include <stdio.h>
     78 #endif
     79 
     80 // *****************************************************************************
     81 // class SimpleDateFormat
     82 // *****************************************************************************
     83 
     84 U_NAMESPACE_BEGIN
     85 
     86 /**
     87  * Last-resort string to use for "GMT" when constructing time zone strings.
     88  */
     89 // For time zones that have no names, use strings GMT+minutes and
     90 // GMT-minutes. For instance, in France the time zone is GMT+60.
     91 // Also accepted are GMT+H:MM or GMT-H:MM.
     92 // Currently not being used
     93 //static const UChar gGmt[]      = {0x0047, 0x004D, 0x0054, 0x0000};         // "GMT"
     94 //static const UChar gGmtPlus[]  = {0x0047, 0x004D, 0x0054, 0x002B, 0x0000}; // "GMT+"
     95 //static const UChar gGmtMinus[] = {0x0047, 0x004D, 0x0054, 0x002D, 0x0000}; // "GMT-"
     96 //static const UChar gDefGmtPat[]       = {0x0047, 0x004D, 0x0054, 0x007B, 0x0030, 0x007D, 0x0000}; /* GMT{0} */
     97 //static const UChar gDefGmtNegHmsPat[] = {0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0x0000}; /* -HH:mm:ss */
     98 //static const UChar gDefGmtNegHmPat[]  = {0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x0000}; /* -HH:mm */
     99 //static const UChar gDefGmtPosHmsPat[] = {0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0x0000}; /* +HH:mm:ss */
    100 //static const UChar gDefGmtPosHmPat[]  = {0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x0000}; /* +HH:mm */
    101 //static const UChar gUt[]       = {0x0055, 0x0054, 0x0000};  // "UT"
    102 //static const UChar gUtc[]      = {0x0055, 0x0054, 0x0043, 0x0000};  // "UT"
    103 
    104 typedef enum GmtPatSize {
    105     kGmtLen = 3,
    106     kGmtPatLen = 6,
    107     kNegHmsLen = 9,
    108     kNegHmLen = 6,
    109     kPosHmsLen = 9,
    110     kPosHmLen = 6,
    111     kUtLen = 2,
    112     kUtcLen = 3
    113 } GmtPatSize;
    114 
    115 // Stuff needed for numbering system overrides
    116 
    117 typedef enum OvrStrType {
    118     kOvrStrDate = 0,
    119     kOvrStrTime = 1,
    120     kOvrStrBoth = 2
    121 } OvrStrType;
    122 
    123 static const UDateFormatField kDateFields[] = {
    124     UDAT_YEAR_FIELD,
    125     UDAT_MONTH_FIELD,
    126     UDAT_DATE_FIELD,
    127     UDAT_DAY_OF_YEAR_FIELD,
    128     UDAT_DAY_OF_WEEK_IN_MONTH_FIELD,
    129     UDAT_WEEK_OF_YEAR_FIELD,
    130     UDAT_WEEK_OF_MONTH_FIELD,
    131     UDAT_YEAR_WOY_FIELD,
    132     UDAT_EXTENDED_YEAR_FIELD,
    133     UDAT_JULIAN_DAY_FIELD,
    134     UDAT_STANDALONE_DAY_FIELD,
    135     UDAT_STANDALONE_MONTH_FIELD,
    136     UDAT_QUARTER_FIELD,
    137     UDAT_STANDALONE_QUARTER_FIELD,
    138     UDAT_YEAR_NAME_FIELD,
    139     UDAT_RELATED_YEAR_FIELD };
    140 static const int8_t kDateFieldsCount = 16;
    141 
    142 static const UDateFormatField kTimeFields[] = {
    143     UDAT_HOUR_OF_DAY1_FIELD,
    144     UDAT_HOUR_OF_DAY0_FIELD,
    145     UDAT_MINUTE_FIELD,
    146     UDAT_SECOND_FIELD,
    147     UDAT_FRACTIONAL_SECOND_FIELD,
    148     UDAT_HOUR1_FIELD,
    149     UDAT_HOUR0_FIELD,
    150     UDAT_MILLISECONDS_IN_DAY_FIELD,
    151     UDAT_TIMEZONE_RFC_FIELD,
    152     UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD };
    153 static const int8_t kTimeFieldsCount = 10;
    154 
    155 
    156 // This is a pattern-of-last-resort used when we can't load a usable pattern out
    157 // of a resource.
    158 static const UChar gDefaultPattern[] =
    159 {
    160     0x79, 0x79, 0x79, 0x79, 0x4D, 0x4D, 0x64, 0x64, 0x20, 0x68, 0x68, 0x3A, 0x6D, 0x6D, 0x20, 0x61, 0
    161 };  /* "yyyyMMdd hh:mm a" */
    162 
    163 // This prefix is designed to NEVER MATCH real text, in order to
    164 // suppress the parsing of negative numbers.  Adjust as needed (if
    165 // this becomes valid Unicode).
    166 static const UChar SUPPRESS_NEGATIVE_PREFIX[] = {0xAB00, 0};
    167 
    168 /**
    169  * These are the tags we expect to see in normal resource bundle files associated
    170  * with a locale.
    171  */
    172 static const UChar QUOTE = 0x27; // Single quote
    173 
    174 /*
    175  * The field range check bias for each UDateFormatField.
    176  * The bias is added to the minimum and maximum values
    177  * before they are compared to the parsed number.
    178  * For example, the calendar stores zero-based month numbers
    179  * but the parsed month numbers start at 1, so the bias is 1.
    180  *
    181  * A value of -1 means that the value is not checked.
    182  */
    183 static const int32_t gFieldRangeBias[] = {
    184     -1,  // 'G' - UDAT_ERA_FIELD
    185     -1,  // 'y' - UDAT_YEAR_FIELD
    186      1,  // 'M' - UDAT_MONTH_FIELD
    187      0,  // 'd' - UDAT_DATE_FIELD
    188     -1,  // 'k' - UDAT_HOUR_OF_DAY1_FIELD
    189     -1,  // 'H' - UDAT_HOUR_OF_DAY0_FIELD
    190      0,  // 'm' - UDAT_MINUTE_FIELD
    191      0,  // 's' - UDAT_SECOND_FIELD
    192     -1,  // 'S' - UDAT_FRACTIONAL_SECOND_FIELD (0-999?)
    193     -1,  // 'E' - UDAT_DAY_OF_WEEK_FIELD (1-7?)
    194     -1,  // 'D' - UDAT_DAY_OF_YEAR_FIELD (1 - 366?)
    195     -1,  // 'F' - UDAT_DAY_OF_WEEK_IN_MONTH_FIELD (1-5?)
    196     -1,  // 'w' - UDAT_WEEK_OF_YEAR_FIELD (1-52?)
    197     -1,  // 'W' - UDAT_WEEK_OF_MONTH_FIELD (1-5?)
    198     -1,  // 'a' - UDAT_AM_PM_FIELD
    199     -1,  // 'h' - UDAT_HOUR1_FIELD
    200     -1,  // 'K' - UDAT_HOUR0_FIELD
    201     -1,  // 'z' - UDAT_TIMEZONE_FIELD
    202     -1,  // 'Y' - UDAT_YEAR_WOY_FIELD
    203     -1,  // 'e' - UDAT_DOW_LOCAL_FIELD
    204     -1,  // 'u' - UDAT_EXTENDED_YEAR_FIELD
    205     -1,  // 'g' - UDAT_JULIAN_DAY_FIELD
    206     -1,  // 'A' - UDAT_MILLISECONDS_IN_DAY_FIELD
    207     -1,  // 'Z' - UDAT_TIMEZONE_RFC_FIELD
    208     -1,  // 'v' - UDAT_TIMEZONE_GENERIC_FIELD
    209      0,  // 'c' - UDAT_STANDALONE_DAY_FIELD
    210      1,  // 'L' - UDAT_STANDALONE_MONTH_FIELD
    211     -1,  // 'Q' - UDAT_QUARTER_FIELD (1-4?)
    212     -1,  // 'q' - UDAT_STANDALONE_QUARTER_FIELD
    213     -1,  // 'V' - UDAT_TIMEZONE_SPECIAL_FIELD
    214     -1,  // 'U' - UDAT_YEAR_NAME_FIELD
    215     -1,  // 'O' - UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD
    216     -1,  // 'X' - UDAT_TIMEZONE_ISO_FIELD
    217     -1,  // 'x' - UDAT_TIMEZONE_ISO_LOCAL_FIELD
    218     -1,  // 'r' - UDAT_RELATED_YEAR_FIELD
    219 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
    220     -1,  // ':' - UDAT_TIME_SEPARATOR_FIELD
    221 #else
    222     -1,  // (no pattern character currently) - UDAT_TIME_SEPARATOR_FIELD
    223 #endif
    224 };
    225 
    226 // When calendar uses hebr numbering (i.e. he@calendar=hebrew),
    227 // offset the years within the current millenium down to 1-999
    228 static const int32_t HEBREW_CAL_CUR_MILLENIUM_START_YEAR = 5000;
    229 static const int32_t HEBREW_CAL_CUR_MILLENIUM_END_YEAR = 6000;
    230 
    231 static UMutex LOCK = U_MUTEX_INITIALIZER;
    232 
    233 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleDateFormat)
    234 
    235 SimpleDateFormat::NSOverride::~NSOverride() {
    236     if (snf != NULL) {
    237         snf->removeRef();
    238     }
    239 }
    240 
    241 
    242 void SimpleDateFormat::NSOverride::free() {
    243     NSOverride *cur = this;
    244     while (cur) {
    245         NSOverride *next = cur->next;
    246         delete cur;
    247         cur = next;
    248     }
    249 }
    250 
    251 // no matter what the locale's default number format looked like, we want
    252 // to modify it so that it doesn't use thousands separators, doesn't always
    253 // show the decimal point, and recognizes integers only when parsing
    254 static void fixNumberFormatForDates(NumberFormat &nf) {
    255     nf.setGroupingUsed(FALSE);
    256     DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(&nf);
    257     if (decfmt != NULL) {
    258         decfmt->setDecimalSeparatorAlwaysShown(FALSE);
    259     }
    260     nf.setParseIntegerOnly(TRUE);
    261     nf.setMinimumFractionDigits(0); // To prevent "Jan 1.00, 1997.00"
    262 }
    263 
    264 static const SharedNumberFormat *createSharedNumberFormat(
    265         NumberFormat *nfToAdopt) {
    266     fixNumberFormatForDates(*nfToAdopt);
    267     const SharedNumberFormat *result = new SharedNumberFormat(nfToAdopt);
    268     if (result == NULL) {
    269         delete nfToAdopt;
    270     }
    271     return result;
    272 }
    273 
    274 static const SharedNumberFormat *createSharedNumberFormat(
    275         const Locale &loc, UErrorCode &status) {
    276     NumberFormat *nf = NumberFormat::createInstance(loc, status);
    277     if (U_FAILURE(status)) {
    278         return NULL;
    279     }
    280     const SharedNumberFormat *result = createSharedNumberFormat(nf);
    281     if (result == NULL) {
    282         status = U_MEMORY_ALLOCATION_ERROR;
    283     }
    284     return result;
    285 }
    286 
    287 static const SharedNumberFormat **allocSharedNumberFormatters() {
    288     const SharedNumberFormat **result = (const SharedNumberFormat**)
    289             uprv_malloc(UDAT_FIELD_COUNT * sizeof(const SharedNumberFormat*));
    290     if (result == NULL) {
    291         return NULL;
    292     }
    293     for (int32_t i = 0; i < UDAT_FIELD_COUNT; ++i) {
    294         result[i] = NULL;
    295     }
    296     return result;
    297 }
    298 
    299 static void freeSharedNumberFormatters(const SharedNumberFormat ** list) {
    300     for (int32_t i = 0; i < UDAT_FIELD_COUNT; ++i) {
    301         SharedObject::clearPtr(list[i]);
    302     }
    303     uprv_free(list);
    304 }
    305 
    306 const NumberFormat *SimpleDateFormat::getNumberFormatByIndex(
    307         UDateFormatField index) const {
    308     if (fSharedNumberFormatters == NULL ||
    309         fSharedNumberFormatters[index] == NULL) {
    310         return fNumberFormat;
    311     }
    312     return &(**fSharedNumberFormatters[index]);
    313 }
    314 
    315 class SimpleDateFormatMutableNFNode {
    316  public:
    317     const NumberFormat *key;
    318     NumberFormat *value;
    319     SimpleDateFormatMutableNFNode()
    320             : key(NULL), value(NULL) { }
    321     ~SimpleDateFormatMutableNFNode() {
    322         delete value;
    323     }
    324  private:
    325     SimpleDateFormatMutableNFNode(const SimpleDateFormatMutableNFNode &);
    326     SimpleDateFormatMutableNFNode &operator=(const SimpleDateFormatMutableNFNode &);
    327 };
    328 
    329 // Single threaded cache of non const NumberFormats. Designed to be stack
    330 // allocated and used for a single format call.
    331 class SimpleDateFormatMutableNFs : public UMemory {
    332  public:
    333     SimpleDateFormatMutableNFs() {
    334     }
    335 
    336     // Returns a non-const clone of nf which can be safely modified.
    337     // Subsequent calls with same nf will return the same non-const clone.
    338     // This object maintains ownership of all returned non-const
    339     // NumberFormat objects. On memory allocation error returns NULL.
    340     // Caller must check for NULL return value.
    341     NumberFormat *get(const NumberFormat *nf) {
    342         if (nf == NULL) {
    343             return NULL;
    344         }
    345         int32_t idx = 0;
    346         while (nodes[idx].value) {
    347             if (nf == nodes[idx].key) {
    348                 return nodes[idx].value;
    349             }
    350             ++idx;
    351         }
    352         U_ASSERT(idx < UDAT_FIELD_COUNT);
    353         nodes[idx].key = nf;
    354         nodes[idx].value = (NumberFormat *) nf->clone();
    355         return nodes[idx].value;
    356     }
    357  private:
    358     // +1 extra for sentinel. If each field had its own NumberFormat, this
    359     // cache would have to allocate UDAT_FIELD_COUNT mutable versions worst
    360     // case.
    361     SimpleDateFormatMutableNFNode nodes[UDAT_FIELD_COUNT + 1];
    362     SimpleDateFormatMutableNFs(const SimpleDateFormatMutableNFs &);
    363     SimpleDateFormatMutableNFs &operator=(const SimpleDateFormatMutableNFs &);
    364 };
    365 
    366 //----------------------------------------------------------------------
    367 
    368 SimpleDateFormat::~SimpleDateFormat()
    369 {
    370     delete fSymbols;
    371     if (fSharedNumberFormatters) {
    372         freeSharedNumberFormatters(fSharedNumberFormatters);
    373     }
    374     if (fTimeZoneFormat) {
    375         delete fTimeZoneFormat;
    376     }
    377 
    378 #if !UCONFIG_NO_BREAK_ITERATION
    379     delete fCapitalizationBrkIter;
    380 #endif
    381 }
    382 
    383 //----------------------------------------------------------------------
    384 
    385 SimpleDateFormat::SimpleDateFormat(UErrorCode& status)
    386   :   fLocale(Locale::getDefault()),
    387       fSymbols(NULL),
    388       fTimeZoneFormat(NULL),
    389       fSharedNumberFormatters(NULL),
    390       fCapitalizationBrkIter(NULL)
    391 {
    392     initializeBooleanAttributes();
    393     construct(kShort, (EStyle) (kShort + kDateOffset), fLocale, status);
    394     initializeDefaultCentury();
    395 }
    396 
    397 //----------------------------------------------------------------------
    398 
    399 SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
    400                                    UErrorCode &status)
    401 :   fPattern(pattern),
    402     fLocale(Locale::getDefault()),
    403     fSymbols(NULL),
    404     fTimeZoneFormat(NULL),
    405     fSharedNumberFormatters(NULL),
    406     fCapitalizationBrkIter(NULL)
    407 {
    408     fDateOverride.setToBogus();
    409     fTimeOverride.setToBogus();
    410     initializeBooleanAttributes();
    411     initializeCalendar(NULL,fLocale,status);
    412     fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
    413     initialize(fLocale, status);
    414     initializeDefaultCentury();
    415 
    416 }
    417 //----------------------------------------------------------------------
    418 
    419 SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
    420                                    const UnicodeString& override,
    421                                    UErrorCode &status)
    422 :   fPattern(pattern),
    423     fLocale(Locale::getDefault()),
    424     fSymbols(NULL),
    425     fTimeZoneFormat(NULL),
    426     fSharedNumberFormatters(NULL),
    427     fCapitalizationBrkIter(NULL)
    428 {
    429     fDateOverride.setTo(override);
    430     fTimeOverride.setToBogus();
    431     initializeBooleanAttributes();
    432     initializeCalendar(NULL,fLocale,status);
    433     fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
    434     initialize(fLocale, status);
    435     initializeDefaultCentury();
    436 
    437     processOverrideString(fLocale,override,kOvrStrBoth,status);
    438 
    439 }
    440 
    441 //----------------------------------------------------------------------
    442 
    443 SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
    444                                    const Locale& locale,
    445                                    UErrorCode& status)
    446 :   fPattern(pattern),
    447     fLocale(locale),
    448     fTimeZoneFormat(NULL),
    449     fSharedNumberFormatters(NULL),
    450     fCapitalizationBrkIter(NULL)
    451 {
    452 
    453     fDateOverride.setToBogus();
    454     fTimeOverride.setToBogus();
    455     initializeBooleanAttributes();
    456 
    457     initializeCalendar(NULL,fLocale,status);
    458     fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
    459     initialize(fLocale, status);
    460     initializeDefaultCentury();
    461 }
    462 
    463 //----------------------------------------------------------------------
    464 
    465 SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
    466                                    const UnicodeString& override,
    467                                    const Locale& locale,
    468                                    UErrorCode& status)
    469 :   fPattern(pattern),
    470     fLocale(locale),
    471     fTimeZoneFormat(NULL),
    472     fSharedNumberFormatters(NULL),
    473     fCapitalizationBrkIter(NULL)
    474 {
    475 
    476     fDateOverride.setTo(override);
    477     fTimeOverride.setToBogus();
    478     initializeBooleanAttributes();
    479 
    480     initializeCalendar(NULL,fLocale,status);
    481     fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
    482     initialize(fLocale, status);
    483     initializeDefaultCentury();
    484 
    485     processOverrideString(locale,override,kOvrStrBoth,status);
    486 
    487 }
    488 
    489 //----------------------------------------------------------------------
    490 
    491 SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
    492                                    DateFormatSymbols* symbolsToAdopt,
    493                                    UErrorCode& status)
    494 :   fPattern(pattern),
    495     fLocale(Locale::getDefault()),
    496     fSymbols(symbolsToAdopt),
    497     fTimeZoneFormat(NULL),
    498     fSharedNumberFormatters(NULL),
    499     fCapitalizationBrkIter(NULL)
    500 {
    501 
    502     fDateOverride.setToBogus();
    503     fTimeOverride.setToBogus();
    504     initializeBooleanAttributes();
    505 
    506     initializeCalendar(NULL,fLocale,status);
    507     initialize(fLocale, status);
    508     initializeDefaultCentury();
    509 }
    510 
    511 //----------------------------------------------------------------------
    512 
    513 SimpleDateFormat::SimpleDateFormat(const UnicodeString& pattern,
    514                                    const DateFormatSymbols& symbols,
    515                                    UErrorCode& status)
    516 :   fPattern(pattern),
    517     fLocale(Locale::getDefault()),
    518     fSymbols(new DateFormatSymbols(symbols)),
    519     fTimeZoneFormat(NULL),
    520     fSharedNumberFormatters(NULL),
    521     fCapitalizationBrkIter(NULL)
    522 {
    523 
    524     fDateOverride.setToBogus();
    525     fTimeOverride.setToBogus();
    526     initializeBooleanAttributes();
    527 
    528     initializeCalendar(NULL, fLocale, status);
    529     initialize(fLocale, status);
    530     initializeDefaultCentury();
    531 }
    532 
    533 //----------------------------------------------------------------------
    534 
    535 // Not for public consumption; used by DateFormat
    536 SimpleDateFormat::SimpleDateFormat(EStyle timeStyle,
    537                                    EStyle dateStyle,
    538                                    const Locale& locale,
    539                                    UErrorCode& status)
    540 :   fLocale(locale),
    541     fSymbols(NULL),
    542     fTimeZoneFormat(NULL),
    543     fSharedNumberFormatters(NULL),
    544     fCapitalizationBrkIter(NULL)
    545 {
    546     initializeBooleanAttributes();
    547     construct(timeStyle, dateStyle, fLocale, status);
    548     if(U_SUCCESS(status)) {
    549       initializeDefaultCentury();
    550     }
    551 }
    552 
    553 //----------------------------------------------------------------------
    554 
    555 /**
    556  * Not for public consumption; used by DateFormat.  This constructor
    557  * never fails.  If the resource data is not available, it uses the
    558  * the last resort symbols.
    559  */
    560 SimpleDateFormat::SimpleDateFormat(const Locale& locale,
    561                                    UErrorCode& status)
    562 :   fPattern(gDefaultPattern),
    563     fLocale(locale),
    564     fSymbols(NULL),
    565     fTimeZoneFormat(NULL),
    566     fSharedNumberFormatters(NULL),
    567     fCapitalizationBrkIter(NULL)
    568 {
    569     if (U_FAILURE(status)) return;
    570     initializeBooleanAttributes();
    571     initializeCalendar(NULL, fLocale, status);
    572     fSymbols = DateFormatSymbols::createForLocale(fLocale, status);
    573     if (U_FAILURE(status))
    574     {
    575         status = U_ZERO_ERROR;
    576         delete fSymbols;
    577         // This constructor doesn't fail; it uses last resort data
    578         fSymbols = new DateFormatSymbols(status);
    579         /* test for NULL */
    580         if (fSymbols == 0) {
    581             status = U_MEMORY_ALLOCATION_ERROR;
    582             return;
    583         }
    584     }
    585 
    586     fDateOverride.setToBogus();
    587     fTimeOverride.setToBogus();
    588 
    589     initialize(fLocale, status);
    590     if(U_SUCCESS(status)) {
    591       initializeDefaultCentury();
    592     }
    593 }
    594 
    595 //----------------------------------------------------------------------
    596 
    597 SimpleDateFormat::SimpleDateFormat(const SimpleDateFormat& other)
    598 :   DateFormat(other),
    599     fLocale(other.fLocale),
    600     fSymbols(NULL),
    601     fTimeZoneFormat(NULL),
    602     fSharedNumberFormatters(NULL),
    603     fCapitalizationBrkIter(NULL)
    604 {
    605     initializeBooleanAttributes();
    606     *this = other;
    607 }
    608 
    609 //----------------------------------------------------------------------
    610 
    611 SimpleDateFormat& SimpleDateFormat::operator=(const SimpleDateFormat& other)
    612 {
    613     if (this == &other) {
    614         return *this;
    615     }
    616     DateFormat::operator=(other);
    617     fDateOverride = other.fDateOverride;
    618     fTimeOverride = other.fTimeOverride;
    619 
    620     delete fSymbols;
    621     fSymbols = NULL;
    622 
    623     if (other.fSymbols)
    624         fSymbols = new DateFormatSymbols(*other.fSymbols);
    625 
    626     fDefaultCenturyStart         = other.fDefaultCenturyStart;
    627     fDefaultCenturyStartYear     = other.fDefaultCenturyStartYear;
    628     fHaveDefaultCentury          = other.fHaveDefaultCentury;
    629 
    630     fPattern = other.fPattern;
    631     fHasMinute = other.fHasMinute;
    632     fHasSecond = other.fHasSecond;
    633 
    634     // TimeZoneFormat in ICU4C only depends on a locale for now
    635     if (fLocale != other.fLocale) {
    636         delete fTimeZoneFormat;
    637         fTimeZoneFormat = NULL; // forces lazy instantiation with the other locale
    638         fLocale = other.fLocale;
    639     }
    640 
    641 #if !UCONFIG_NO_BREAK_ITERATION
    642     if (other.fCapitalizationBrkIter != NULL) {
    643         fCapitalizationBrkIter = (other.fCapitalizationBrkIter)->clone();
    644     }
    645 #endif
    646 
    647     if (fSharedNumberFormatters != NULL) {
    648         freeSharedNumberFormatters(fSharedNumberFormatters);
    649         fSharedNumberFormatters = NULL;
    650     }
    651     if (other.fSharedNumberFormatters != NULL) {
    652         fSharedNumberFormatters = allocSharedNumberFormatters();
    653         if (fSharedNumberFormatters) {
    654             for (int32_t i = 0; i < UDAT_FIELD_COUNT; ++i) {
    655                 SharedObject::copyPtr(
    656                         other.fSharedNumberFormatters[i],
    657                         fSharedNumberFormatters[i]);
    658             }
    659         }
    660     }
    661 
    662     return *this;
    663 }
    664 
    665 //----------------------------------------------------------------------
    666 
    667 Format*
    668 SimpleDateFormat::clone() const
    669 {
    670     return new SimpleDateFormat(*this);
    671 }
    672 
    673 //----------------------------------------------------------------------
    674 
    675 UBool
    676 SimpleDateFormat::operator==(const Format& other) const
    677 {
    678     if (DateFormat::operator==(other)) {
    679         // The DateFormat::operator== check for fCapitalizationContext equality above
    680         //   is sufficient to check equality of all derived context-related data.
    681         // DateFormat::operator== guarantees following cast is safe
    682         SimpleDateFormat* that = (SimpleDateFormat*)&other;
    683         return (fPattern             == that->fPattern &&
    684                 fSymbols             != NULL && // Check for pathological object
    685                 that->fSymbols       != NULL && // Check for pathological object
    686                 *fSymbols            == *that->fSymbols &&
    687                 fHaveDefaultCentury  == that->fHaveDefaultCentury &&
    688                 fDefaultCenturyStart == that->fDefaultCenturyStart);
    689     }
    690     return FALSE;
    691 }
    692 
    693 //----------------------------------------------------------------------
    694 
    695 void SimpleDateFormat::construct(EStyle timeStyle,
    696                                  EStyle dateStyle,
    697                                  const Locale& locale,
    698                                  UErrorCode& status)
    699 {
    700     // called by several constructors to load pattern data from the resources
    701     if (U_FAILURE(status)) return;
    702 
    703     // We will need the calendar to know what type of symbols to load.
    704     initializeCalendar(NULL, locale, status);
    705     if (U_FAILURE(status)) return;
    706 
    707     // Load date time patterns directly from resources.
    708     const char* cType = fCalendar ? fCalendar->getType() : NULL;
    709     LocalUResourceBundlePointer bundle(ures_open(NULL, locale.getBaseName(), &status));
    710     if (U_FAILURE(status)) return;
    711 
    712     UBool cTypeIsGregorian = TRUE;
    713     LocalUResourceBundlePointer dateTimePatterns;
    714     if (cType != NULL && uprv_strcmp(cType, "gregorian") != 0) {
    715         CharString resourcePath("calendar/", status);
    716         resourcePath.append(cType, status).append("/DateTimePatterns", status);
    717         dateTimePatterns.adoptInstead(
    718             ures_getByKeyWithFallback(bundle.getAlias(), resourcePath.data(),
    719                                       (UResourceBundle*)NULL, &status));
    720         cTypeIsGregorian = FALSE;
    721     }
    722 
    723     // Check for "gregorian" fallback.
    724     if (cTypeIsGregorian || status == U_MISSING_RESOURCE_ERROR) {
    725         status = U_ZERO_ERROR;
    726         dateTimePatterns.adoptInstead(
    727             ures_getByKeyWithFallback(bundle.getAlias(),
    728                                       "calendar/gregorian/DateTimePatterns",
    729                                       (UResourceBundle*)NULL, &status));
    730     }
    731     if (U_FAILURE(status)) return;
    732 
    733     LocalUResourceBundlePointer currentBundle;
    734 
    735     if (ures_getSize(dateTimePatterns.getAlias()) <= kDateTime)
    736     {
    737         status = U_INVALID_FORMAT_ERROR;
    738         return;
    739     }
    740 
    741     setLocaleIDs(ures_getLocaleByType(dateTimePatterns.getAlias(), ULOC_VALID_LOCALE, &status),
    742                  ures_getLocaleByType(dateTimePatterns.getAlias(), ULOC_ACTUAL_LOCALE, &status));
    743 
    744     // create a symbols object from the locale
    745     fSymbols = DateFormatSymbols::createForLocale(locale, status);
    746     if (U_FAILURE(status)) return;
    747     /* test for NULL */
    748     if (fSymbols == 0) {
    749         status = U_MEMORY_ALLOCATION_ERROR;
    750         return;
    751     }
    752 
    753     const UChar *resStr,*ovrStr;
    754     int32_t resStrLen,ovrStrLen = 0;
    755     fDateOverride.setToBogus();
    756     fTimeOverride.setToBogus();
    757 
    758     // if the pattern should include both date and time information, use the date/time
    759     // pattern string as a guide to tell use how to glue together the appropriate date
    760     // and time pattern strings.
    761     if ((timeStyle != kNone) && (dateStyle != kNone))
    762     {
    763         currentBundle.adoptInstead(
    764                 ures_getByIndex(dateTimePatterns.getAlias(), (int32_t)timeStyle, NULL, &status));
    765         if (U_FAILURE(status)) {
    766            status = U_INVALID_FORMAT_ERROR;
    767            return;
    768         }
    769         switch (ures_getType(currentBundle.getAlias())) {
    770             case URES_STRING: {
    771                resStr = ures_getString(currentBundle.getAlias(), &resStrLen, &status);
    772                break;
    773             }
    774             case URES_ARRAY: {
    775                resStr = ures_getStringByIndex(currentBundle.getAlias(), 0, &resStrLen, &status);
    776                ovrStr = ures_getStringByIndex(currentBundle.getAlias(), 1, &ovrStrLen, &status);
    777                fTimeOverride.setTo(TRUE, ovrStr, ovrStrLen);
    778                break;
    779             }
    780             default: {
    781                status = U_INVALID_FORMAT_ERROR;
    782                return;
    783             }
    784         }
    785 
    786         UnicodeString tempus1(TRUE, resStr, resStrLen);
    787 
    788         currentBundle.adoptInstead(
    789                 ures_getByIndex(dateTimePatterns.getAlias(), (int32_t)dateStyle, NULL, &status));
    790         if (U_FAILURE(status)) {
    791            status = U_INVALID_FORMAT_ERROR;
    792            return;
    793         }
    794         switch (ures_getType(currentBundle.getAlias())) {
    795             case URES_STRING: {
    796                resStr = ures_getString(currentBundle.getAlias(), &resStrLen, &status);
    797                break;
    798             }
    799             case URES_ARRAY: {
    800                resStr = ures_getStringByIndex(currentBundle.getAlias(), 0, &resStrLen, &status);
    801                ovrStr = ures_getStringByIndex(currentBundle.getAlias(), 1, &ovrStrLen, &status);
    802                fDateOverride.setTo(TRUE, ovrStr, ovrStrLen);
    803                break;
    804             }
    805             default: {
    806                status = U_INVALID_FORMAT_ERROR;
    807                return;
    808             }
    809         }
    810 
    811         UnicodeString tempus2(TRUE, resStr, resStrLen);
    812 
    813         int32_t glueIndex = kDateTime;
    814         int32_t patternsSize = ures_getSize(dateTimePatterns.getAlias());
    815         if (patternsSize >= (kDateTimeOffset + kShort + 1)) {
    816             // Get proper date time format
    817             glueIndex = (int32_t)(kDateTimeOffset + (dateStyle - kDateOffset));
    818         }
    819 
    820         resStr = ures_getStringByIndex(dateTimePatterns.getAlias(), glueIndex, &resStrLen, &status);
    821         SimpleFormatter(UnicodeString(TRUE, resStr, resStrLen), 2, 2, status).
    822                 format(tempus1, tempus2, fPattern, status);
    823     }
    824     // if the pattern includes just time data or just date date, load the appropriate
    825     // pattern string from the resources
    826     // setTo() - see DateFormatSymbols::assignArray comments
    827     else if (timeStyle != kNone) {
    828         currentBundle.adoptInstead(
    829                 ures_getByIndex(dateTimePatterns.getAlias(), (int32_t)timeStyle, NULL, &status));
    830         if (U_FAILURE(status)) {
    831            status = U_INVALID_FORMAT_ERROR;
    832            return;
    833         }
    834         switch (ures_getType(currentBundle.getAlias())) {
    835             case URES_STRING: {
    836                resStr = ures_getString(currentBundle.getAlias(), &resStrLen, &status);
    837                break;
    838             }
    839             case URES_ARRAY: {
    840                resStr = ures_getStringByIndex(currentBundle.getAlias(), 0, &resStrLen, &status);
    841                ovrStr = ures_getStringByIndex(currentBundle.getAlias(), 1, &ovrStrLen, &status);
    842                fDateOverride.setTo(TRUE, ovrStr, ovrStrLen);
    843                break;
    844             }
    845             default: {
    846                status = U_INVALID_FORMAT_ERROR;
    847                return;
    848             }
    849         }
    850         fPattern.setTo(TRUE, resStr, resStrLen);
    851     }
    852     else if (dateStyle != kNone) {
    853         currentBundle.adoptInstead(
    854                 ures_getByIndex(dateTimePatterns.getAlias(), (int32_t)dateStyle, NULL, &status));
    855         if (U_FAILURE(status)) {
    856            status = U_INVALID_FORMAT_ERROR;
    857            return;
    858         }
    859         switch (ures_getType(currentBundle.getAlias())) {
    860             case URES_STRING: {
    861                resStr = ures_getString(currentBundle.getAlias(), &resStrLen, &status);
    862                break;
    863             }
    864             case URES_ARRAY: {
    865                resStr = ures_getStringByIndex(currentBundle.getAlias(), 0, &resStrLen, &status);
    866                ovrStr = ures_getStringByIndex(currentBundle.getAlias(), 1, &ovrStrLen, &status);
    867                fDateOverride.setTo(TRUE, ovrStr, ovrStrLen);
    868                break;
    869             }
    870             default: {
    871                status = U_INVALID_FORMAT_ERROR;
    872                return;
    873             }
    874         }
    875         fPattern.setTo(TRUE, resStr, resStrLen);
    876     }
    877 
    878     // and if it includes _neither_, that's an error
    879     else
    880         status = U_INVALID_FORMAT_ERROR;
    881 
    882     // finally, finish initializing by creating a Calendar and a NumberFormat
    883     initialize(locale, status);
    884 }
    885 
    886 //----------------------------------------------------------------------
    887 
    888 Calendar*
    889 SimpleDateFormat::initializeCalendar(TimeZone* adoptZone, const Locale& locale, UErrorCode& status)
    890 {
    891     if(!U_FAILURE(status)) {
    892         fCalendar = Calendar::createInstance(adoptZone?adoptZone:TimeZone::createDefault(), locale, status);
    893     }
    894     return fCalendar;
    895 }
    896 
    897 void
    898 SimpleDateFormat::initialize(const Locale& locale,
    899                              UErrorCode& status)
    900 {
    901     if (U_FAILURE(status)) return;
    902 
    903     // We don't need to check that the row count is >= 1, since all 2d arrays have at
    904     // least one row
    905     fNumberFormat = NumberFormat::createInstance(locale, status);
    906     if (fNumberFormat != NULL && U_SUCCESS(status))
    907     {
    908         fixNumberFormatForDates(*fNumberFormat);
    909         //fNumberFormat->setLenient(TRUE); // Java uses a custom DateNumberFormat to format/parse
    910 
    911         initNumberFormatters(locale,status);
    912 
    913     }
    914     else if (U_SUCCESS(status))
    915     {
    916         status = U_MISSING_RESOURCE_ERROR;
    917     }
    918 
    919     parsePattern();
    920 }
    921 
    922 /* Initialize the fields we use to disambiguate ambiguous years. Separate
    923  * so we can call it from readObject().
    924  */
    925 void SimpleDateFormat::initializeDefaultCentury()
    926 {
    927   if(fCalendar) {
    928     fHaveDefaultCentury = fCalendar->haveDefaultCentury();
    929     if(fHaveDefaultCentury) {
    930       fDefaultCenturyStart = fCalendar->defaultCenturyStart();
    931       fDefaultCenturyStartYear = fCalendar->defaultCenturyStartYear();
    932     } else {
    933       fDefaultCenturyStart = DBL_MIN;
    934       fDefaultCenturyStartYear = -1;
    935     }
    936   }
    937 }
    938 
    939 /*
    940  * Initialize the boolean attributes. Separate so we can call it from all constructors.
    941  */
    942 void SimpleDateFormat::initializeBooleanAttributes()
    943 {
    944     UErrorCode status = U_ZERO_ERROR;
    945 
    946     setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status);
    947     setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status);
    948     setBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, true, status);
    949     setBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, true, status);
    950 }
    951 
    952 /* Define one-century window into which to disambiguate dates using
    953  * two-digit years. Make public in JDK 1.2.
    954  */
    955 void SimpleDateFormat::parseAmbiguousDatesAsAfter(UDate startDate, UErrorCode& status)
    956 {
    957     if(U_FAILURE(status)) {
    958         return;
    959     }
    960     if(!fCalendar) {
    961       status = U_ILLEGAL_ARGUMENT_ERROR;
    962       return;
    963     }
    964 
    965     fCalendar->setTime(startDate, status);
    966     if(U_SUCCESS(status)) {
    967         fHaveDefaultCentury = TRUE;
    968         fDefaultCenturyStart = startDate;
    969         fDefaultCenturyStartYear = fCalendar->get(UCAL_YEAR, status);
    970     }
    971 }
    972 
    973 //----------------------------------------------------------------------
    974 
    975 UnicodeString&
    976 SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo, FieldPosition& pos) const
    977 {
    978   UErrorCode status = U_ZERO_ERROR;
    979   FieldPositionOnlyHandler handler(pos);
    980   return _format(cal, appendTo, handler, status);
    981 }
    982 
    983 //----------------------------------------------------------------------
    984 
    985 UnicodeString&
    986 SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo,
    987                          FieldPositionIterator* posIter, UErrorCode& status) const
    988 {
    989   FieldPositionIteratorHandler handler(posIter, status);
    990   return _format(cal, appendTo, handler, status);
    991 }
    992 
    993 //----------------------------------------------------------------------
    994 
    995 UnicodeString&
    996 SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo,
    997                             FieldPositionHandler& handler, UErrorCode& status) const
    998 {
    999     if ( U_FAILURE(status) ) {
   1000        return appendTo;
   1001     }
   1002     Calendar* workCal = &cal;
   1003     Calendar* calClone = NULL;
   1004     if (&cal != fCalendar && uprv_strcmp(cal.getType(), fCalendar->getType()) != 0) {
   1005         // Different calendar type
   1006         // We use the time and time zone from the input calendar, but
   1007         // do not use the input calendar for field calculation.
   1008         calClone = fCalendar->clone();
   1009         if (calClone != NULL) {
   1010             UDate t = cal.getTime(status);
   1011             calClone->setTime(t, status);
   1012             calClone->setTimeZone(cal.getTimeZone());
   1013             workCal = calClone;
   1014         } else {
   1015             status = U_MEMORY_ALLOCATION_ERROR;
   1016             return appendTo;
   1017         }
   1018     }
   1019 
   1020     UBool inQuote = FALSE;
   1021     UChar prevCh = 0;
   1022     int32_t count = 0;
   1023     int32_t fieldNum = 0;
   1024     UDisplayContext capitalizationContext = getContext(UDISPCTX_TYPE_CAPITALIZATION, status);
   1025 
   1026     // Create temporary cache of mutable number format objects. This way
   1027     // subFormat won't have to clone the const NumberFormat for each field.
   1028     // if several fields share the same NumberFormat, which will almost
   1029     // always be the case, this is a big save.
   1030     SimpleDateFormatMutableNFs mutableNFs;
   1031     // loop through the pattern string character by character
   1032     for (int32_t i = 0; i < fPattern.length() && U_SUCCESS(status); ++i) {
   1033         UChar ch = fPattern[i];
   1034 
   1035         // Use subFormat() to format a repeated pattern character
   1036         // when a different pattern or non-pattern character is seen
   1037         if (ch != prevCh && count > 0) {
   1038             subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++, handler, *workCal, mutableNFs, status);
   1039             count = 0;
   1040         }
   1041         if (ch == QUOTE) {
   1042             // Consecutive single quotes are a single quote literal,
   1043             // either outside of quotes or between quotes
   1044             if ((i+1) < fPattern.length() && fPattern[i+1] == QUOTE) {
   1045                 appendTo += (UChar)QUOTE;
   1046                 ++i;
   1047             } else {
   1048                 inQuote = ! inQuote;
   1049             }
   1050         }
   1051         else if (!inQuote && isSyntaxChar(ch)) {
   1052             // ch is a date-time pattern character to be interpreted
   1053             // by subFormat(); count the number of times it is repeated
   1054             prevCh = ch;
   1055             ++count;
   1056         }
   1057         else {
   1058             // Append quoted characters and unquoted non-pattern characters
   1059             appendTo += ch;
   1060         }
   1061     }
   1062 
   1063     // Format the last item in the pattern, if any
   1064     if (count > 0) {
   1065         subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++, handler, *workCal, mutableNFs, status);
   1066     }
   1067 
   1068     if (calClone != NULL) {
   1069         delete calClone;
   1070     }
   1071 
   1072     return appendTo;
   1073 }
   1074 
   1075 //----------------------------------------------------------------------
   1076 
   1077 /* Map calendar field into calendar field level.
   1078  * the larger the level, the smaller the field unit.
   1079  * For example, UCAL_ERA level is 0, UCAL_YEAR level is 10,
   1080  * UCAL_MONTH level is 20.
   1081  * NOTE: if new fields adds in, the table needs to update.
   1082  */
   1083 const int32_t
   1084 SimpleDateFormat::fgCalendarFieldToLevel[] =
   1085 {
   1086     /*GyM*/ 0, 10, 20,
   1087     /*wW*/ 20, 30,
   1088     /*dDEF*/ 30, 20, 30, 30,
   1089     /*ahHm*/ 40, 50, 50, 60,
   1090     /*sS*/ 70, 80,
   1091     /*z?Y*/ 0, 0, 10,
   1092     /*eug*/ 30, 10, 0,
   1093     /*A?.*/ 40, 0, 0
   1094 };
   1095 
   1096 int32_t SimpleDateFormat::getLevelFromChar(UChar ch) {
   1097     // Map date field LETTER into calendar field level.
   1098     // the larger the level, the smaller the field unit.
   1099     // NOTE: if new fields adds in, the table needs to update.
   1100     static const int32_t mapCharToLevel[] = {
   1101             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   1102         //
   1103             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   1104         //       !   "   #   $   %   &   '   (   )   *   +   ,   -   .   /
   1105             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   1106 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
   1107         //   0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?
   1108             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  0, -1, -1, -1, -1, -1,
   1109 #else
   1110         //   0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?
   1111             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
   1112 #endif
   1113         //   @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
   1114             -1, 40, -1, -1, 20, 30, 30,  0, 50, -1, -1, 50, 20, 20, -1,  0,
   1115         //   P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _
   1116             -1, 20, -1, 80, -1, 10,  0, 30,  0, 10,  0, -1, -1, -1, -1, -1,
   1117         //   `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
   1118             -1, 40, -1, 30, 30, 30, -1,  0, 50, -1, -1, 50,  0, 60, -1, -1,
   1119         //   p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~
   1120             -1, 20, 10, 70, -1, 10,  0, 20,  0, 10,  0, -1, -1, -1, -1, -1
   1121     };
   1122 
   1123     return ch < UPRV_LENGTHOF(mapCharToLevel) ? mapCharToLevel[ch] : -1;
   1124 }
   1125 
   1126 UBool SimpleDateFormat::isSyntaxChar(UChar ch) {
   1127     static const UBool mapCharToIsSyntax[] = {
   1128         //
   1129         FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
   1130         //
   1131         FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
   1132         //
   1133         FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
   1134         //
   1135         FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
   1136         //         !      "      #      $      %      &      '
   1137         FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
   1138         //  (      )      *      +      ,      -      .      /
   1139         FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
   1140         //  0      1      2      3      4      5      6      7
   1141         FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
   1142 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
   1143         //  8      9      :      ;      <      =      >      ?
   1144         FALSE, FALSE,  TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,
   1145 #else
   1146         //  8      9      :      ;      <      =      >      ?
   1147         FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
   1148 #endif
   1149         //  @      A      B      C      D      E      F      G
   1150         FALSE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,
   1151         //  H      I      J      K      L      M      N      O
   1152          TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,
   1153         //  P      Q      R      S      T      U      V      W
   1154          TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,
   1155         //  X      Y      Z      [      \      ]      ^      _
   1156          TRUE,  TRUE,  TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,
   1157         //  `      a      b      c      d      e      f      g
   1158         FALSE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,
   1159         //  h      i      j      k      l      m      n      o
   1160          TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,
   1161         //  p      q      r      s      t      u      v      w
   1162          TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,
   1163         //  x      y      z      {      |      }      ~
   1164          TRUE,  TRUE,  TRUE, FALSE, FALSE, FALSE, FALSE, FALSE
   1165     };
   1166 
   1167     return ch < UPRV_LENGTHOF(mapCharToIsSyntax) ? mapCharToIsSyntax[ch] : FALSE;
   1168 }
   1169 
   1170 // Map index into pattern character string to Calendar field number.
   1171 const UCalendarDateFields
   1172 SimpleDateFormat::fgPatternIndexToCalendarField[] =
   1173 {
   1174     /*GyM*/ UCAL_ERA, UCAL_YEAR, UCAL_MONTH,
   1175     /*dkH*/ UCAL_DATE, UCAL_HOUR_OF_DAY, UCAL_HOUR_OF_DAY,
   1176     /*msS*/ UCAL_MINUTE, UCAL_SECOND, UCAL_MILLISECOND,
   1177     /*EDF*/ UCAL_DAY_OF_WEEK, UCAL_DAY_OF_YEAR, UCAL_DAY_OF_WEEK_IN_MONTH,
   1178     /*wWa*/ UCAL_WEEK_OF_YEAR, UCAL_WEEK_OF_MONTH, UCAL_AM_PM,
   1179     /*hKz*/ UCAL_HOUR, UCAL_HOUR, UCAL_ZONE_OFFSET,
   1180     /*Yeu*/ UCAL_YEAR_WOY, UCAL_DOW_LOCAL, UCAL_EXTENDED_YEAR,
   1181     /*gAZ*/ UCAL_JULIAN_DAY, UCAL_MILLISECONDS_IN_DAY, UCAL_ZONE_OFFSET,
   1182     /*v*/   UCAL_ZONE_OFFSET,
   1183     /*c*/   UCAL_DOW_LOCAL,
   1184     /*L*/   UCAL_MONTH,
   1185     /*Q*/   UCAL_MONTH,
   1186     /*q*/   UCAL_MONTH,
   1187     /*V*/   UCAL_ZONE_OFFSET,
   1188     /*U*/   UCAL_YEAR,
   1189     /*O*/   UCAL_ZONE_OFFSET,
   1190     /*Xx*/  UCAL_ZONE_OFFSET, UCAL_ZONE_OFFSET,
   1191     /*r*/   UCAL_EXTENDED_YEAR,
   1192     /*bB*/   UCAL_FIELD_COUNT, UCAL_FIELD_COUNT,  // no mappings to calendar fields
   1193 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
   1194     /*:*/   UCAL_FIELD_COUNT, /* => no useful mapping to any calendar field */
   1195 #else
   1196     /*no pattern char for UDAT_TIME_SEPARATOR_FIELD*/   UCAL_FIELD_COUNT, /* => no useful mapping to any calendar field */
   1197 #endif
   1198 };
   1199 
   1200 // Map index into pattern character string to DateFormat field number
   1201 const UDateFormatField
   1202 SimpleDateFormat::fgPatternIndexToDateFormatField[] = {
   1203     /*GyM*/ UDAT_ERA_FIELD, UDAT_YEAR_FIELD, UDAT_MONTH_FIELD,
   1204     /*dkH*/ UDAT_DATE_FIELD, UDAT_HOUR_OF_DAY1_FIELD, UDAT_HOUR_OF_DAY0_FIELD,
   1205     /*msS*/ UDAT_MINUTE_FIELD, UDAT_SECOND_FIELD, UDAT_FRACTIONAL_SECOND_FIELD,
   1206     /*EDF*/ UDAT_DAY_OF_WEEK_FIELD, UDAT_DAY_OF_YEAR_FIELD, UDAT_DAY_OF_WEEK_IN_MONTH_FIELD,
   1207     /*wWa*/ UDAT_WEEK_OF_YEAR_FIELD, UDAT_WEEK_OF_MONTH_FIELD, UDAT_AM_PM_FIELD,
   1208     /*hKz*/ UDAT_HOUR1_FIELD, UDAT_HOUR0_FIELD, UDAT_TIMEZONE_FIELD,
   1209     /*Yeu*/ UDAT_YEAR_WOY_FIELD, UDAT_DOW_LOCAL_FIELD, UDAT_EXTENDED_YEAR_FIELD,
   1210     /*gAZ*/ UDAT_JULIAN_DAY_FIELD, UDAT_MILLISECONDS_IN_DAY_FIELD, UDAT_TIMEZONE_RFC_FIELD,
   1211     /*v*/   UDAT_TIMEZONE_GENERIC_FIELD,
   1212     /*c*/   UDAT_STANDALONE_DAY_FIELD,
   1213     /*L*/   UDAT_STANDALONE_MONTH_FIELD,
   1214     /*Q*/   UDAT_QUARTER_FIELD,
   1215     /*q*/   UDAT_STANDALONE_QUARTER_FIELD,
   1216     /*V*/   UDAT_TIMEZONE_SPECIAL_FIELD,
   1217     /*U*/   UDAT_YEAR_NAME_FIELD,
   1218     /*O*/   UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD,
   1219     /*Xx*/  UDAT_TIMEZONE_ISO_FIELD, UDAT_TIMEZONE_ISO_LOCAL_FIELD,
   1220     /*r*/   UDAT_RELATED_YEAR_FIELD,
   1221     /*bB*/  UDAT_AM_PM_MIDNIGHT_NOON_FIELD, UDAT_FLEXIBLE_DAY_PERIOD_FIELD,
   1222 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
   1223     /*:*/   UDAT_TIME_SEPARATOR_FIELD,
   1224 #else
   1225     /*no pattern char for UDAT_TIME_SEPARATOR_FIELD*/   UDAT_TIME_SEPARATOR_FIELD,
   1226 #endif
   1227 };
   1228 
   1229 //----------------------------------------------------------------------
   1230 
   1231 /**
   1232  * Append symbols[value] to dst.  Make sure the array index is not out
   1233  * of bounds.
   1234  */
   1235 static inline void
   1236 _appendSymbol(UnicodeString& dst,
   1237               int32_t value,
   1238               const UnicodeString* symbols,
   1239               int32_t symbolsCount) {
   1240     U_ASSERT(0 <= value && value < symbolsCount);
   1241     if (0 <= value && value < symbolsCount) {
   1242         dst += symbols[value];
   1243     }
   1244 }
   1245 
   1246 static inline void
   1247 _appendSymbolWithMonthPattern(UnicodeString& dst, int32_t value, const UnicodeString* symbols, int32_t symbolsCount,
   1248               const UnicodeString* monthPattern, UErrorCode& status) {
   1249     U_ASSERT(0 <= value && value < symbolsCount);
   1250     if (0 <= value && value < symbolsCount) {
   1251         if (monthPattern == NULL) {
   1252             dst += symbols[value];
   1253         } else {
   1254             SimpleFormatter(*monthPattern, 1, 1, status).format(symbols[value], dst, status);
   1255         }
   1256     }
   1257 }
   1258 
   1259 //----------------------------------------------------------------------
   1260 void
   1261 SimpleDateFormat::initNumberFormatters(const Locale &locale,UErrorCode &status) {
   1262     if (U_FAILURE(status)) {
   1263         return;
   1264     }
   1265     if ( fDateOverride.isBogus() && fTimeOverride.isBogus() ) {
   1266         return;
   1267     }
   1268     umtx_lock(&LOCK);
   1269     if (fSharedNumberFormatters == NULL) {
   1270         fSharedNumberFormatters = allocSharedNumberFormatters();
   1271         if (fSharedNumberFormatters == NULL) {
   1272             status = U_MEMORY_ALLOCATION_ERROR;
   1273         }
   1274     }
   1275     umtx_unlock(&LOCK);
   1276 
   1277     if (U_FAILURE(status)) {
   1278         return;
   1279     }
   1280 
   1281     processOverrideString(locale,fDateOverride,kOvrStrDate,status);
   1282     processOverrideString(locale,fTimeOverride,kOvrStrTime,status);
   1283 }
   1284 
   1285 void
   1286 SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeString &str, int8_t type, UErrorCode &status) {
   1287     if (str.isBogus() || U_FAILURE(status)) {
   1288         return;
   1289     }
   1290 
   1291     int32_t start = 0;
   1292     int32_t len;
   1293     UnicodeString nsName;
   1294     UnicodeString ovrField;
   1295     UBool moreToProcess = TRUE;
   1296     NSOverride *overrideList = NULL;
   1297 
   1298     while (moreToProcess) {
   1299         int32_t delimiterPosition = str.indexOf((UChar)ULOC_KEYWORD_ITEM_SEPARATOR_UNICODE,start);
   1300         if (delimiterPosition == -1) {
   1301             moreToProcess = FALSE;
   1302             len = str.length() - start;
   1303         } else {
   1304             len = delimiterPosition - start;
   1305         }
   1306         UnicodeString currentString(str,start,len);
   1307         int32_t equalSignPosition = currentString.indexOf((UChar)ULOC_KEYWORD_ASSIGN_UNICODE,0);
   1308         if (equalSignPosition == -1) { // Simple override string such as "hebrew"
   1309             nsName.setTo(currentString);
   1310             ovrField.setToBogus();
   1311         } else { // Field specific override string such as "y=hebrew"
   1312             nsName.setTo(currentString,equalSignPosition+1);
   1313             ovrField.setTo(currentString,0,1); // We just need the first character.
   1314         }
   1315 
   1316         int32_t nsNameHash = nsName.hashCode();
   1317         // See if the numbering system is in the override list, if not, then add it.
   1318         NSOverride *cur = overrideList;
   1319         const SharedNumberFormat *snf = NULL;
   1320         UBool found = FALSE;
   1321         while ( cur && !found ) {
   1322             if ( cur->hash == nsNameHash ) {
   1323                 snf = cur->snf;
   1324                 found = TRUE;
   1325             }
   1326             cur = cur->next;
   1327         }
   1328 
   1329         if (!found) {
   1330            LocalPointer<NSOverride> cur(new NSOverride);
   1331            if (!cur.isNull()) {
   1332                char kw[ULOC_KEYWORD_AND_VALUES_CAPACITY];
   1333                uprv_strcpy(kw,"numbers=");
   1334                nsName.extract(0,len,kw+8,ULOC_KEYWORD_AND_VALUES_CAPACITY-8,US_INV);
   1335 
   1336                Locale ovrLoc(locale.getLanguage(),locale.getCountry(),locale.getVariant(),kw);
   1337                cur->hash = nsNameHash;
   1338                cur->next = overrideList;
   1339                SharedObject::copyPtr(
   1340                        createSharedNumberFormat(ovrLoc, status), cur->snf);
   1341                if (U_FAILURE(status)) {
   1342                    if (overrideList) {
   1343                        overrideList->free();
   1344                    }
   1345                    return;
   1346                }
   1347                snf = cur->snf;
   1348                overrideList = cur.orphan();
   1349            } else {
   1350                status = U_MEMORY_ALLOCATION_ERROR;
   1351                if (overrideList) {
   1352                    overrideList->free();
   1353                }
   1354                return;
   1355            }
   1356         }
   1357 
   1358         // Now that we have an appropriate number formatter, fill in the appropriate spaces in the
   1359         // number formatters table.
   1360         if (ovrField.isBogus()) {
   1361             switch (type) {
   1362                 case kOvrStrDate:
   1363                 case kOvrStrBoth: {
   1364                     for ( int8_t i=0 ; i<kDateFieldsCount; i++ ) {
   1365                         SharedObject::copyPtr(snf, fSharedNumberFormatters[kDateFields[i]]);
   1366                     }
   1367                     if (type==kOvrStrDate) {
   1368                         break;
   1369                     }
   1370                     U_FALLTHROUGH;
   1371                 }
   1372                 case kOvrStrTime : {
   1373                     for ( int8_t i=0 ; i<kTimeFieldsCount; i++ ) {
   1374                         SharedObject::copyPtr(snf, fSharedNumberFormatters[kTimeFields[i]]);
   1375                     }
   1376                     break;
   1377                 }
   1378             }
   1379         } else {
   1380            // if the pattern character is unrecognized, signal an error and bail out
   1381            UDateFormatField patternCharIndex =
   1382               DateFormatSymbols::getPatternCharIndex(ovrField.charAt(0));
   1383            if (patternCharIndex == UDAT_FIELD_COUNT) {
   1384                status = U_INVALID_FORMAT_ERROR;
   1385                if (overrideList) {
   1386                    overrideList->free();
   1387                }
   1388                return;
   1389            }
   1390            SharedObject::copyPtr(snf, fSharedNumberFormatters[patternCharIndex]);
   1391         }
   1392 
   1393         start = delimiterPosition + 1;
   1394     }
   1395     if (overrideList) {
   1396         overrideList->free();
   1397     }
   1398 }
   1399 
   1400 //---------------------------------------------------------------------
   1401 void
   1402 SimpleDateFormat::subFormat(UnicodeString &appendTo,
   1403                             UChar ch,
   1404                             int32_t count,
   1405                             UDisplayContext capitalizationContext,
   1406                             int32_t fieldNum,
   1407                             FieldPositionHandler& handler,
   1408                             Calendar& cal,
   1409                             SimpleDateFormatMutableNFs &mutableNFs,
   1410                             UErrorCode& status) const
   1411 {
   1412     if (U_FAILURE(status)) {
   1413         return;
   1414     }
   1415 
   1416     // this function gets called by format() to produce the appropriate substitution
   1417     // text for an individual pattern symbol (e.g., "HH" or "yyyy")
   1418 
   1419     UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(ch);
   1420     const int32_t maxIntCount = 10;
   1421     int32_t beginOffset = appendTo.length();
   1422     NumberFormat *currentNumberFormat;
   1423     DateFormatSymbols::ECapitalizationContextUsageType capContextUsageType = DateFormatSymbols::kCapContextUsageOther;
   1424 
   1425     UBool isHebrewCalendar = (uprv_strcmp(cal.getType(),"hebrew") == 0);
   1426     UBool isChineseCalendar = (uprv_strcmp(cal.getType(),"chinese") == 0 || uprv_strcmp(cal.getType(),"dangi") == 0);
   1427 
   1428     // if the pattern character is unrecognized, signal an error and dump out
   1429     if (patternCharIndex == UDAT_FIELD_COUNT)
   1430     {
   1431         if (ch != 0x6C) { // pattern char 'l' (SMALL LETTER L) just gets ignored
   1432             status = U_INVALID_FORMAT_ERROR;
   1433         }
   1434         return;
   1435     }
   1436 
   1437     UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex];
   1438     int32_t value = 0;
   1439     // Don't get value unless it is useful
   1440     if (field < UCAL_FIELD_COUNT) {
   1441         value = (patternCharIndex != UDAT_RELATED_YEAR_FIELD)? cal.get(field, status): cal.getRelatedYear(status);
   1442     }
   1443     if (U_FAILURE(status)) {
   1444         return;
   1445     }
   1446 
   1447     currentNumberFormat = mutableNFs.get(getNumberFormatByIndex(patternCharIndex));
   1448     if (currentNumberFormat == NULL) {
   1449         status = U_MEMORY_ALLOCATION_ERROR;
   1450         return;
   1451     }
   1452     UnicodeString hebr("hebr", 4, US_INV);
   1453 
   1454     switch (patternCharIndex) {
   1455 
   1456     // for any "G" symbol, write out the appropriate era string
   1457     // "GGGG" is wide era name, "GGGGG" is narrow era name, anything else is abbreviated name
   1458     case UDAT_ERA_FIELD:
   1459         if (isChineseCalendar) {
   1460             zeroPaddingNumber(currentNumberFormat,appendTo, value, 1, 9); // as in ICU4J
   1461         } else {
   1462             if (count == 5) {
   1463                 _appendSymbol(appendTo, value, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount);
   1464                 capContextUsageType = DateFormatSymbols::kCapContextUsageEraNarrow;
   1465             } else if (count == 4) {
   1466                 _appendSymbol(appendTo, value, fSymbols->fEraNames, fSymbols->fEraNamesCount);
   1467                 capContextUsageType = DateFormatSymbols::kCapContextUsageEraWide;
   1468             } else {
   1469                 _appendSymbol(appendTo, value, fSymbols->fEras, fSymbols->fErasCount);
   1470                 capContextUsageType = DateFormatSymbols::kCapContextUsageEraAbbrev;
   1471             }
   1472         }
   1473         break;
   1474 
   1475      case UDAT_YEAR_NAME_FIELD:
   1476         if (fSymbols->fShortYearNames != NULL && value <= fSymbols->fShortYearNamesCount) {
   1477             // the Calendar YEAR field runs 1 through 60 for cyclic years
   1478             _appendSymbol(appendTo, value - 1, fSymbols->fShortYearNames, fSymbols->fShortYearNamesCount);
   1479             break;
   1480         }
   1481         // else fall through to numeric year handling, do not break here
   1482         U_FALLTHROUGH;
   1483 
   1484    // OLD: for "yyyy", write out the whole year; for "yy", write out the last 2 digits
   1485     // NEW: UTS#35:
   1486 //Year         y     yy     yyy     yyyy     yyyyy
   1487 //AD 1         1     01     001     0001     00001
   1488 //AD 12       12     12     012     0012     00012
   1489 //AD 123     123     23     123     0123     00123
   1490 //AD 1234   1234     34    1234     1234     01234
   1491 //AD 12345 12345     45   12345    12345     12345
   1492     case UDAT_YEAR_FIELD:
   1493     case UDAT_YEAR_WOY_FIELD:
   1494         if (fDateOverride.compare(hebr)==0 && value>HEBREW_CAL_CUR_MILLENIUM_START_YEAR && value<HEBREW_CAL_CUR_MILLENIUM_END_YEAR) {
   1495             value-=HEBREW_CAL_CUR_MILLENIUM_START_YEAR;
   1496         }
   1497         if(count == 2)
   1498             zeroPaddingNumber(currentNumberFormat, appendTo, value, 2, 2);
   1499         else
   1500             zeroPaddingNumber(currentNumberFormat, appendTo, value, count, maxIntCount);
   1501         break;
   1502 
   1503     // for "MMMM"/"LLLL", write out the whole month name, for "MMM"/"LLL", write out the month
   1504     // abbreviation, for "M"/"L" or "MM"/"LL", write out the month as a number with the
   1505     // appropriate number of digits
   1506     // for "MMMMM"/"LLLLL", use the narrow form
   1507     case UDAT_MONTH_FIELD:
   1508     case UDAT_STANDALONE_MONTH_FIELD:
   1509         if ( isHebrewCalendar ) {
   1510            HebrewCalendar *hc = (HebrewCalendar*)&cal;
   1511            if (hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value == 6 && count >= 3 )
   1512                value = 13; // Show alternate form for Adar II in leap years in Hebrew calendar.
   1513            if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6 && count < 3 )
   1514                value--; // Adjust the month number down 1 in Hebrew non-leap years, i.e. Adar is 6, not 7.
   1515         }
   1516         {
   1517             int32_t isLeapMonth = (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount)?
   1518                         cal.get(UCAL_IS_LEAP_MONTH, status): 0;
   1519             // should consolidate the next section by using arrays of pointers & counts for the right symbols...
   1520             if (count == 5) {
   1521                 if (patternCharIndex == UDAT_MONTH_FIELD) {
   1522                     _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fNarrowMonths, fSymbols->fNarrowMonthsCount,
   1523                             (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatNarrow]): NULL, status);
   1524                 } else {
   1525                     _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneNarrowMonths, fSymbols->fStandaloneNarrowMonthsCount,
   1526                             (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneNarrow]): NULL, status);
   1527                 }
   1528                 capContextUsageType = DateFormatSymbols::kCapContextUsageMonthNarrow;
   1529             } else if (count == 4) {
   1530                 if (patternCharIndex == UDAT_MONTH_FIELD) {
   1531                     _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fMonths, fSymbols->fMonthsCount,
   1532                             (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatWide]): NULL, status);
   1533                     capContextUsageType = DateFormatSymbols::kCapContextUsageMonthFormat;
   1534                 } else {
   1535                     _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneMonths, fSymbols->fStandaloneMonthsCount,
   1536                             (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneWide]): NULL, status);
   1537                     capContextUsageType = DateFormatSymbols::kCapContextUsageMonthStandalone;
   1538                 }
   1539             } else if (count == 3) {
   1540                 if (patternCharIndex == UDAT_MONTH_FIELD) {
   1541                     _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fShortMonths, fSymbols->fShortMonthsCount,
   1542                             (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatAbbrev]): NULL, status);
   1543                     capContextUsageType = DateFormatSymbols::kCapContextUsageMonthFormat;
   1544                 } else {
   1545                     _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneShortMonths, fSymbols->fStandaloneShortMonthsCount,
   1546                             (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneAbbrev]): NULL, status);
   1547                     capContextUsageType = DateFormatSymbols::kCapContextUsageMonthStandalone;
   1548                 }
   1549             } else {
   1550                 UnicodeString monthNumber;
   1551                 zeroPaddingNumber(currentNumberFormat,monthNumber, value + 1, count, maxIntCount);
   1552                 _appendSymbolWithMonthPattern(appendTo, 0, &monthNumber, 1,
   1553                         (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternNumeric]): NULL, status);
   1554             }
   1555         }
   1556         break;
   1557 
   1558     // for "k" and "kk", write out the hour, adjusting midnight to appear as "24"
   1559     case UDAT_HOUR_OF_DAY1_FIELD:
   1560         if (value == 0)
   1561             zeroPaddingNumber(currentNumberFormat,appendTo, cal.getMaximum(UCAL_HOUR_OF_DAY) + 1, count, maxIntCount);
   1562         else
   1563             zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
   1564         break;
   1565 
   1566     case UDAT_FRACTIONAL_SECOND_FIELD:
   1567         // Fractional seconds left-justify
   1568         {
   1569             currentNumberFormat->setMinimumIntegerDigits((count > 3) ? 3 : count);
   1570             currentNumberFormat->setMaximumIntegerDigits(maxIntCount);
   1571             if (count == 1) {
   1572                 value /= 100;
   1573             } else if (count == 2) {
   1574                 value /= 10;
   1575             }
   1576             FieldPosition p(FieldPosition::DONT_CARE);
   1577             currentNumberFormat->format(value, appendTo, p);
   1578             if (count > 3) {
   1579                 currentNumberFormat->setMinimumIntegerDigits(count - 3);
   1580                 currentNumberFormat->format((int32_t)0, appendTo, p);
   1581             }
   1582         }
   1583         break;
   1584 
   1585     // for "ee" or "e", use local numeric day-of-the-week
   1586     // for "EEEEEE" or "eeeeee", write out the short day-of-the-week name
   1587     // for "EEEEE" or "eeeee", write out the narrow day-of-the-week name
   1588     // for "EEEE" or "eeee", write out the wide day-of-the-week name
   1589     // for "EEE" or "EE" or "E" or "eee", write out the abbreviated day-of-the-week name
   1590     case UDAT_DOW_LOCAL_FIELD:
   1591         if ( count < 3 ) {
   1592             zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
   1593             break;
   1594         }
   1595         // fall through to EEEEE-EEE handling, but for that we don't want local day-of-week,
   1596         // we want standard day-of-week, so first fix value to work for EEEEE-EEE.
   1597         value = cal.get(UCAL_DAY_OF_WEEK, status);
   1598         if (U_FAILURE(status)) {
   1599             return;
   1600         }
   1601         // fall through, do not break here
   1602         U_FALLTHROUGH;
   1603     case UDAT_DAY_OF_WEEK_FIELD:
   1604         if (count == 5) {
   1605             _appendSymbol(appendTo, value, fSymbols->fNarrowWeekdays,
   1606                           fSymbols->fNarrowWeekdaysCount);
   1607             capContextUsageType = DateFormatSymbols::kCapContextUsageDayNarrow;
   1608         } else if (count == 4) {
   1609             _appendSymbol(appendTo, value, fSymbols->fWeekdays,
   1610                           fSymbols->fWeekdaysCount);
   1611             capContextUsageType = DateFormatSymbols::kCapContextUsageDayFormat;
   1612         } else if (count == 6) {
   1613             _appendSymbol(appendTo, value, fSymbols->fShorterWeekdays,
   1614                           fSymbols->fShorterWeekdaysCount);
   1615             capContextUsageType = DateFormatSymbols::kCapContextUsageDayFormat;
   1616         } else {
   1617             _appendSymbol(appendTo, value, fSymbols->fShortWeekdays,
   1618                           fSymbols->fShortWeekdaysCount);
   1619             capContextUsageType = DateFormatSymbols::kCapContextUsageDayFormat;
   1620         }
   1621         break;
   1622 
   1623     // for "ccc", write out the abbreviated day-of-the-week name
   1624     // for "cccc", write out the wide day-of-the-week name
   1625     // for "ccccc", use the narrow day-of-the-week name
   1626     // for "ccccc", use the short day-of-the-week name
   1627     case UDAT_STANDALONE_DAY_FIELD:
   1628         if ( count < 3 ) {
   1629             zeroPaddingNumber(currentNumberFormat,appendTo, value, 1, maxIntCount);
   1630             break;
   1631         }
   1632         // fall through to alpha DOW handling, but for that we don't want local day-of-week,
   1633         // we want standard day-of-week, so first fix value.
   1634         value = cal.get(UCAL_DAY_OF_WEEK, status);
   1635         if (U_FAILURE(status)) {
   1636             return;
   1637         }
   1638         if (count == 5) {
   1639             _appendSymbol(appendTo, value, fSymbols->fStandaloneNarrowWeekdays,
   1640                           fSymbols->fStandaloneNarrowWeekdaysCount);
   1641             capContextUsageType = DateFormatSymbols::kCapContextUsageDayNarrow;
   1642         } else if (count == 4) {
   1643             _appendSymbol(appendTo, value, fSymbols->fStandaloneWeekdays,
   1644                           fSymbols->fStandaloneWeekdaysCount);
   1645             capContextUsageType = DateFormatSymbols::kCapContextUsageDayStandalone;
   1646         } else if (count == 6) {
   1647             _appendSymbol(appendTo, value, fSymbols->fStandaloneShorterWeekdays,
   1648                           fSymbols->fStandaloneShorterWeekdaysCount);
   1649             capContextUsageType = DateFormatSymbols::kCapContextUsageDayStandalone;
   1650         } else { // count == 3
   1651             _appendSymbol(appendTo, value, fSymbols->fStandaloneShortWeekdays,
   1652                           fSymbols->fStandaloneShortWeekdaysCount);
   1653             capContextUsageType = DateFormatSymbols::kCapContextUsageDayStandalone;
   1654         }
   1655         break;
   1656 
   1657     // for "a" symbol, write out the whole AM/PM string
   1658     case UDAT_AM_PM_FIELD:
   1659         if (count < 5) {
   1660             _appendSymbol(appendTo, value, fSymbols->fAmPms,
   1661                           fSymbols->fAmPmsCount);
   1662         } else {
   1663             _appendSymbol(appendTo, value, fSymbols->fNarrowAmPms,
   1664                           fSymbols->fNarrowAmPmsCount);
   1665         }
   1666         break;
   1667 
   1668     // if we see pattern character for UDAT_TIME_SEPARATOR_FIELD (none currently defined),
   1669     // write out the time separator string. Leave support in for future definition.
   1670     case UDAT_TIME_SEPARATOR_FIELD:
   1671         {
   1672             UnicodeString separator;
   1673             appendTo += fSymbols->getTimeSeparatorString(separator);
   1674         }
   1675         break;
   1676 
   1677     // for "h" and "hh", write out the hour, adjusting noon and midnight to show up
   1678     // as "12"
   1679     case UDAT_HOUR1_FIELD:
   1680         if (value == 0)
   1681             zeroPaddingNumber(currentNumberFormat,appendTo, cal.getLeastMaximum(UCAL_HOUR) + 1, count, maxIntCount);
   1682         else
   1683             zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
   1684         break;
   1685 
   1686     case UDAT_TIMEZONE_FIELD: // 'z'
   1687     case UDAT_TIMEZONE_RFC_FIELD: // 'Z'
   1688     case UDAT_TIMEZONE_GENERIC_FIELD: // 'v'
   1689     case UDAT_TIMEZONE_SPECIAL_FIELD: // 'V'
   1690     case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD: // 'O'
   1691     case UDAT_TIMEZONE_ISO_FIELD: // 'X'
   1692     case UDAT_TIMEZONE_ISO_LOCAL_FIELD: // 'x'
   1693         {
   1694             UChar zsbuf[ZONE_NAME_U16_MAX];
   1695             UnicodeString zoneString(zsbuf, 0, UPRV_LENGTHOF(zsbuf));
   1696             const TimeZone& tz = cal.getTimeZone();
   1697             UDate date = cal.getTime(status);
   1698             if (U_SUCCESS(status)) {
   1699                 if (patternCharIndex == UDAT_TIMEZONE_FIELD) {
   1700                     if (count < 4) {
   1701                         // "z", "zz", "zzz"
   1702                         tzFormat()->format(UTZFMT_STYLE_SPECIFIC_SHORT, tz, date, zoneString);
   1703                         capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort;
   1704                     } else {
   1705                         // "zzzz" or longer
   1706                         tzFormat()->format(UTZFMT_STYLE_SPECIFIC_LONG, tz, date, zoneString);
   1707                         capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneLong;
   1708                     }
   1709                 }
   1710                 else if (patternCharIndex == UDAT_TIMEZONE_RFC_FIELD) {
   1711                     if (count < 4) {
   1712                         // "Z"
   1713                         tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, tz, date, zoneString);
   1714                     } else if (count == 5) {
   1715                         // "ZZZZZ"
   1716                         tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString);
   1717                     } else {
   1718                         // "ZZ", "ZZZ", "ZZZZ"
   1719                         tzFormat()->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString);
   1720                     }
   1721                 }
   1722                 else if (patternCharIndex == UDAT_TIMEZONE_GENERIC_FIELD) {
   1723                     if (count == 1) {
   1724                         // "v"
   1725                         tzFormat()->format(UTZFMT_STYLE_GENERIC_SHORT, tz, date, zoneString);
   1726                         capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort;
   1727                     } else if (count == 4) {
   1728                         // "vvvv"
   1729                         tzFormat()->format(UTZFMT_STYLE_GENERIC_LONG, tz, date, zoneString);
   1730                         capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneLong;
   1731                     }
   1732                 }
   1733                 else if (patternCharIndex == UDAT_TIMEZONE_SPECIAL_FIELD) {
   1734                     if (count == 1) {
   1735                         // "V"
   1736                         tzFormat()->format(UTZFMT_STYLE_ZONE_ID_SHORT, tz, date, zoneString);
   1737                     } else if (count == 2) {
   1738                         // "VV"
   1739                         tzFormat()->format(UTZFMT_STYLE_ZONE_ID, tz, date, zoneString);
   1740                     } else if (count == 3) {
   1741                         // "VVV"
   1742                         tzFormat()->format(UTZFMT_STYLE_EXEMPLAR_LOCATION, tz, date, zoneString);
   1743                     } else if (count == 4) {
   1744                         // "VVVV"
   1745                         tzFormat()->format(UTZFMT_STYLE_GENERIC_LOCATION, tz, date, zoneString);
   1746                         capContextUsageType = DateFormatSymbols::kCapContextUsageZoneLong;
   1747                     }
   1748                 }
   1749                 else if (patternCharIndex == UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD) {
   1750                     if (count == 1) {
   1751                         // "O"
   1752                         tzFormat()->format(UTZFMT_STYLE_LOCALIZED_GMT_SHORT, tz, date, zoneString);
   1753                     } else if (count == 4) {
   1754                         // "OOOO"
   1755                         tzFormat()->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString);
   1756                     }
   1757                 }
   1758                 else if (patternCharIndex == UDAT_TIMEZONE_ISO_FIELD) {
   1759                     if (count == 1) {
   1760                         // "X"
   1761                         tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_SHORT, tz, date, zoneString);
   1762                     } else if (count == 2) {
   1763                         // "XX"
   1764                         tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_FIXED, tz, date, zoneString);
   1765                     } else if (count == 3) {
   1766                         // "XXX"
   1767                         tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_FIXED, tz, date, zoneString);
   1768                     } else if (count == 4) {
   1769                         // "XXXX"
   1770                         tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_FULL, tz, date, zoneString);
   1771                     } else if (count == 5) {
   1772                         // "XXXXX"
   1773                         tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString);
   1774                     }
   1775                 }
   1776                 else if (patternCharIndex == UDAT_TIMEZONE_ISO_LOCAL_FIELD) {
   1777                     if (count == 1) {
   1778                         // "x"
   1779                         tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_SHORT, tz, date, zoneString);
   1780                     } else if (count == 2) {
   1781                         // "xx"
   1782                         tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FIXED, tz, date, zoneString);
   1783                     } else if (count == 3) {
   1784                         // "xxx"
   1785                         tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FIXED, tz, date, zoneString);
   1786                     } else if (count == 4) {
   1787                         // "xxxx"
   1788                         tzFormat()->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, tz, date, zoneString);
   1789                     } else if (count == 5) {
   1790                         // "xxxxx"
   1791                         tzFormat()->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL, tz, date, zoneString);
   1792                     }
   1793                 }
   1794                 else {
   1795                     U_ASSERT(FALSE);
   1796                 }
   1797             }
   1798             appendTo += zoneString;
   1799         }
   1800         break;
   1801 
   1802     case UDAT_QUARTER_FIELD:
   1803         if (count >= 4)
   1804             _appendSymbol(appendTo, value/3, fSymbols->fQuarters,
   1805                           fSymbols->fQuartersCount);
   1806         else if (count == 3)
   1807             _appendSymbol(appendTo, value/3, fSymbols->fShortQuarters,
   1808                           fSymbols->fShortQuartersCount);
   1809         else
   1810             zeroPaddingNumber(currentNumberFormat,appendTo, (value/3) + 1, count, maxIntCount);
   1811         break;
   1812 
   1813     case UDAT_STANDALONE_QUARTER_FIELD:
   1814         if (count >= 4)
   1815             _appendSymbol(appendTo, value/3, fSymbols->fStandaloneQuarters,
   1816                           fSymbols->fStandaloneQuartersCount);
   1817         else if (count == 3)
   1818             _appendSymbol(appendTo, value/3, fSymbols->fStandaloneShortQuarters,
   1819                           fSymbols->fStandaloneShortQuartersCount);
   1820         else
   1821             zeroPaddingNumber(currentNumberFormat,appendTo, (value/3) + 1, count, maxIntCount);
   1822         break;
   1823 
   1824     case UDAT_AM_PM_MIDNIGHT_NOON_FIELD:
   1825     {
   1826         const UnicodeString *toAppend = NULL;
   1827         int32_t hour = cal.get(UCAL_HOUR_OF_DAY, status);
   1828 
   1829         // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
   1830         // For ICU 57 output of "midnight" is temporarily suppressed.
   1831 
   1832         // For "midnight" and "noon":
   1833         // Time, as displayed, must be exactly noon or midnight.
   1834         // This means minutes and seconds, if present, must be zero.
   1835         if ((/*hour == 0 ||*/ hour == 12) &&
   1836                 (!fHasMinute || cal.get(UCAL_MINUTE, status) == 0) &&
   1837                 (!fHasSecond || cal.get(UCAL_SECOND, status) == 0)) {
   1838             // Stealing am/pm value to use as our array index.
   1839             // It works out: am/midnight are both 0, pm/noon are both 1,
   1840             // 12 am is 12 midnight, and 12 pm is 12 noon.
   1841             int32_t value = cal.get(UCAL_AM_PM, status);
   1842 
   1843             if (count <= 3) {
   1844                 toAppend = &fSymbols->fAbbreviatedDayPeriods[value];
   1845             } else if (count == 4 || count > 5) {
   1846                 toAppend = &fSymbols->fWideDayPeriods[value];
   1847             } else { // count == 5
   1848                 toAppend = &fSymbols->fNarrowDayPeriods[value];
   1849             }
   1850         }
   1851 
   1852         // toAppend is NULL if time isn't exactly midnight or noon (as displayed).
   1853         // toAppend is bogus if time is midnight or noon, but no localized string exists.
   1854         // In either case, fall back to am/pm.
   1855         if (toAppend == NULL || toAppend->isBogus()) {
   1856             // Reformat with identical arguments except ch, now changed to 'a'.
   1857             subFormat(appendTo, 0x61, count, capitalizationContext, fieldNum,
   1858                       handler, cal, mutableNFs, status);
   1859         } else {
   1860             appendTo += *toAppend;
   1861         }
   1862 
   1863         break;
   1864     }
   1865 
   1866     case UDAT_FLEXIBLE_DAY_PERIOD_FIELD:
   1867     {
   1868         // TODO: Maybe fetch the DayperiodRules during initialization (instead of at the first
   1869         // loading of an instance) if a relevant pattern character (b or B) is used.
   1870         const DayPeriodRules *ruleSet = DayPeriodRules::getInstance(this->getSmpFmtLocale(), status);
   1871         if (U_FAILURE(status)) {
   1872             // Data doesn't conform to spec, therefore loading failed.
   1873             break;
   1874         }
   1875         if (ruleSet == NULL) {
   1876             // Data doesn't exist for the locale we're looking for.
   1877             // Falling back to am/pm.
   1878             subFormat(appendTo, 0x61, count, capitalizationContext, fieldNum,
   1879                       handler, cal, mutableNFs, status);
   1880             break;
   1881         }
   1882 
   1883         // Get current display time.
   1884         int32_t hour = cal.get(UCAL_HOUR_OF_DAY, status);
   1885         int32_t minute = 0;
   1886         if (fHasMinute) {
   1887             minute = cal.get(UCAL_MINUTE, status);
   1888         }
   1889         int32_t second = 0;
   1890         if (fHasSecond) {
   1891             second = cal.get(UCAL_SECOND, status);
   1892         }
   1893 
   1894         // Determine day period.
   1895         DayPeriodRules::DayPeriod periodType;
   1896         if (hour == 0 && minute == 0 && second == 0 && ruleSet->hasMidnight()) {
   1897             periodType = DayPeriodRules::DAYPERIOD_MIDNIGHT;
   1898         } else if (hour == 12 && minute == 0 && second == 0 && ruleSet->hasNoon()) {
   1899             periodType = DayPeriodRules::DAYPERIOD_NOON;
   1900         } else {
   1901             periodType = ruleSet->getDayPeriodForHour(hour);
   1902         }
   1903 
   1904         // Rule set exists, therefore periodType can't be UNKNOWN.
   1905         // Get localized string.
   1906         U_ASSERT(periodType != DayPeriodRules::DAYPERIOD_UNKNOWN);
   1907         UnicodeString *toAppend = NULL;
   1908         int32_t index;
   1909 
   1910         // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
   1911         // For ICU 57 output of "midnight" is temporarily suppressed.
   1912 
   1913         if (periodType != DayPeriodRules::DAYPERIOD_AM &&
   1914                 periodType != DayPeriodRules::DAYPERIOD_PM &&
   1915                 periodType != DayPeriodRules::DAYPERIOD_MIDNIGHT) {
   1916             index = (int32_t)periodType;
   1917             if (count <= 3) {
   1918                 toAppend = &fSymbols->fAbbreviatedDayPeriods[index];  // i.e. short
   1919             } else if (count == 4 || count > 5) {
   1920                 toAppend = &fSymbols->fWideDayPeriods[index];
   1921             } else {  // count == 5
   1922                 toAppend = &fSymbols->fNarrowDayPeriods[index];
   1923             }
   1924         }
   1925 
   1926         // Fallback schedule:
   1927         // Midnight/Noon -> General Periods -> AM/PM.
   1928 
   1929         // Midnight/Noon -> General Periods.
   1930         if ((toAppend == NULL || toAppend->isBogus()) &&
   1931                 (periodType == DayPeriodRules::DAYPERIOD_MIDNIGHT ||
   1932                  periodType == DayPeriodRules::DAYPERIOD_NOON)) {
   1933             periodType = ruleSet->getDayPeriodForHour(hour);
   1934             index = (int32_t)periodType;
   1935 
   1936             if (count <= 3) {
   1937                 toAppend = &fSymbols->fAbbreviatedDayPeriods[index];  // i.e. short
   1938             } else if (count == 4 || count > 5) {
   1939                 toAppend = &fSymbols->fWideDayPeriods[index];
   1940             } else {  // count == 5
   1941                 toAppend = &fSymbols->fNarrowDayPeriods[index];
   1942             }
   1943         }
   1944 
   1945         // General Periods -> AM/PM.
   1946         if (periodType == DayPeriodRules::DAYPERIOD_AM ||
   1947             periodType == DayPeriodRules::DAYPERIOD_PM ||
   1948             toAppend->isBogus()) {
   1949             subFormat(appendTo, 0x61, count, capitalizationContext, fieldNum,
   1950                       handler, cal, mutableNFs, status);
   1951         }
   1952         else {
   1953             appendTo += *toAppend;
   1954         }
   1955 
   1956         break;
   1957     }
   1958 
   1959     // all of the other pattern symbols can be formatted as simple numbers with
   1960     // appropriate zero padding
   1961     default:
   1962         zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
   1963         break;
   1964     }
   1965 #if !UCONFIG_NO_BREAK_ITERATION
   1966     // if first field, check to see whether we need to and are able to titlecase it
   1967     if (fieldNum == 0 && u_islower(appendTo.char32At(beginOffset)) && fCapitalizationBrkIter != NULL) {
   1968         UBool titlecase = FALSE;
   1969         switch (capitalizationContext) {
   1970             case UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE:
   1971                 titlecase = TRUE;
   1972                 break;
   1973             case UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU:
   1974                 titlecase = fSymbols->fCapitalization[capContextUsageType][0];
   1975                 break;
   1976             case UDISPCTX_CAPITALIZATION_FOR_STANDALONE:
   1977                 titlecase = fSymbols->fCapitalization[capContextUsageType][1];
   1978                 break;
   1979             default:
   1980                 // titlecase = FALSE;
   1981                 break;
   1982         }
   1983         if (titlecase) {
   1984             UnicodeString firstField(appendTo, beginOffset);
   1985             firstField.toTitle(fCapitalizationBrkIter, fLocale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
   1986             appendTo.replaceBetween(beginOffset, appendTo.length(), firstField);
   1987         }
   1988     }
   1989 #endif
   1990 
   1991     handler.addAttribute(fgPatternIndexToDateFormatField[patternCharIndex], beginOffset, appendTo.length());
   1992 }
   1993 
   1994 //----------------------------------------------------------------------
   1995 
   1996 void SimpleDateFormat::adoptNumberFormat(NumberFormat *formatToAdopt) {
   1997     fixNumberFormatForDates(*formatToAdopt);
   1998     delete fNumberFormat;
   1999     fNumberFormat = formatToAdopt;
   2000 
   2001     // We successfully set the default number format. Now delete the overrides
   2002     // (can't fail).
   2003     if (fSharedNumberFormatters) {
   2004         freeSharedNumberFormatters(fSharedNumberFormatters);
   2005         fSharedNumberFormatters = NULL;
   2006     }
   2007 }
   2008 
   2009 void SimpleDateFormat::adoptNumberFormat(const UnicodeString& fields, NumberFormat *formatToAdopt, UErrorCode &status){
   2010     fixNumberFormatForDates(*formatToAdopt);
   2011     LocalPointer<NumberFormat> fmt(formatToAdopt);
   2012     if (U_FAILURE(status)) {
   2013         return;
   2014     }
   2015 
   2016     // We must ensure fSharedNumberFormatters is allocated.
   2017     if (fSharedNumberFormatters == NULL) {
   2018         fSharedNumberFormatters = allocSharedNumberFormatters();
   2019         if (fSharedNumberFormatters == NULL) {
   2020             status = U_MEMORY_ALLOCATION_ERROR;
   2021             return;
   2022         }
   2023     }
   2024     const SharedNumberFormat *newFormat = createSharedNumberFormat(fmt.orphan());
   2025     if (newFormat == NULL) {
   2026         status = U_MEMORY_ALLOCATION_ERROR;
   2027         return;
   2028     }
   2029     for (int i=0; i<fields.length(); i++) {
   2030         UChar field = fields.charAt(i);
   2031         // if the pattern character is unrecognized, signal an error and bail out
   2032         UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(field);
   2033         if (patternCharIndex == UDAT_FIELD_COUNT) {
   2034             status = U_INVALID_FORMAT_ERROR;
   2035             newFormat->deleteIfZeroRefCount();
   2036             return;
   2037         }
   2038 
   2039         // Set the number formatter in the table
   2040         SharedObject::copyPtr(
   2041                 newFormat, fSharedNumberFormatters[patternCharIndex]);
   2042     }
   2043     newFormat->deleteIfZeroRefCount();
   2044 }
   2045 
   2046 const NumberFormat *
   2047 SimpleDateFormat::getNumberFormatForField(UChar field) const {
   2048     UDateFormatField index = DateFormatSymbols::getPatternCharIndex(field);
   2049     if (index == UDAT_FIELD_COUNT) {
   2050         return NULL;
   2051     }
   2052     return getNumberFormatByIndex(index);
   2053 }
   2054 
   2055 //----------------------------------------------------------------------
   2056 void
   2057 SimpleDateFormat::zeroPaddingNumber(
   2058         NumberFormat *currentNumberFormat,
   2059         UnicodeString &appendTo,
   2060         int32_t value, int32_t minDigits, int32_t maxDigits) const
   2061 {
   2062     if (currentNumberFormat!=NULL) {
   2063         FieldPosition pos(FieldPosition::DONT_CARE);
   2064 
   2065         currentNumberFormat->setMinimumIntegerDigits(minDigits);
   2066         currentNumberFormat->setMaximumIntegerDigits(maxDigits);
   2067         currentNumberFormat->format(value, appendTo, pos);  // 3rd arg is there to speed up processing
   2068     }
   2069 }
   2070 
   2071 //----------------------------------------------------------------------
   2072 
   2073 /**
   2074  * Return true if the given format character, occuring count
   2075  * times, represents a numeric field.
   2076  */
   2077 UBool SimpleDateFormat::isNumeric(UChar formatChar, int32_t count) {
   2078     return DateFormatSymbols::isNumericPatternChar(formatChar, count);
   2079 }
   2080 
   2081 UBool
   2082 SimpleDateFormat::isAtNumericField(const UnicodeString &pattern, int32_t patternOffset) {
   2083     if (patternOffset >= pattern.length()) {
   2084         // not at any field
   2085         return FALSE;
   2086     }
   2087     UChar ch = pattern.charAt(patternOffset);
   2088     UDateFormatField f = DateFormatSymbols::getPatternCharIndex(ch);
   2089     if (f == UDAT_FIELD_COUNT) {
   2090         // not at any field
   2091         return FALSE;
   2092     }
   2093     int32_t i = patternOffset;
   2094     while (pattern.charAt(++i) == ch) {}
   2095     return DateFormatSymbols::isNumericField(f, i - patternOffset);
   2096 }
   2097 
   2098 UBool
   2099 SimpleDateFormat::isAfterNonNumericField(const UnicodeString &pattern, int32_t patternOffset) {
   2100     if (patternOffset <= 0) {
   2101         // not after any field
   2102         return FALSE;
   2103     }
   2104     UChar ch = pattern.charAt(--patternOffset);
   2105     UDateFormatField f = DateFormatSymbols::getPatternCharIndex(ch);
   2106     if (f == UDAT_FIELD_COUNT) {
   2107         // not after any field
   2108         return FALSE;
   2109     }
   2110     int32_t i = patternOffset;
   2111     while (pattern.charAt(--i) == ch) {}
   2112     return !DateFormatSymbols::isNumericField(f, patternOffset - i);
   2113 }
   2114 
   2115 void
   2116 SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition& parsePos) const
   2117 {
   2118     UErrorCode status = U_ZERO_ERROR;
   2119     int32_t pos = parsePos.getIndex();
   2120     if(parsePos.getIndex() < 0) {
   2121         parsePos.setErrorIndex(0);
   2122         return;
   2123     }
   2124     int32_t start = pos;
   2125 
   2126     // Hold the day period until everything else is parsed, because we need
   2127     // the hour to interpret time correctly.
   2128     int32_t dayPeriodInt = -1;
   2129 
   2130     UBool ambiguousYear[] = { FALSE };
   2131     int32_t saveHebrewMonth = -1;
   2132     int32_t count = 0;
   2133     UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
   2134     SimpleDateFormatMutableNFs mutableNFs;
   2135 
   2136     // For parsing abutting numeric fields. 'abutPat' is the
   2137     // offset into 'pattern' of the first of 2 or more abutting
   2138     // numeric fields.  'abutStart' is the offset into 'text'
   2139     // where parsing the fields begins. 'abutPass' starts off as 0
   2140     // and increments each time we try to parse the fields.
   2141     int32_t abutPat = -1; // If >=0, we are in a run of abutting numeric fields
   2142     int32_t abutStart = 0;
   2143     int32_t abutPass = 0;
   2144     UBool inQuote = FALSE;
   2145 
   2146     MessageFormat * numericLeapMonthFormatter = NULL;
   2147 
   2148     Calendar* calClone = NULL;
   2149     Calendar *workCal = &cal;
   2150     if (&cal != fCalendar && uprv_strcmp(cal.getType(), fCalendar->getType()) != 0) {
   2151         // Different calendar type
   2152         // We use the time/zone from the input calendar, but
   2153         // do not use the input calendar for field calculation.
   2154         calClone = fCalendar->clone();
   2155         if (calClone != NULL) {
   2156             calClone->setTime(cal.getTime(status),status);
   2157             if (U_FAILURE(status)) {
   2158                 goto ExitParse;
   2159             }
   2160             calClone->setTimeZone(cal.getTimeZone());
   2161             workCal = calClone;
   2162         } else {
   2163             status = U_MEMORY_ALLOCATION_ERROR;
   2164             goto ExitParse;
   2165         }
   2166     }
   2167 
   2168     if (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount) {
   2169         numericLeapMonthFormatter = new MessageFormat(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternNumeric], fLocale, status);
   2170         if (numericLeapMonthFormatter == NULL) {
   2171              status = U_MEMORY_ALLOCATION_ERROR;
   2172              goto ExitParse;
   2173         } else if (U_FAILURE(status)) {
   2174              goto ExitParse; // this will delete numericLeapMonthFormatter
   2175         }
   2176     }
   2177 
   2178     for (int32_t i=0; i<fPattern.length(); ++i) {
   2179         UChar ch = fPattern.charAt(i);
   2180 
   2181         // Handle alphabetic field characters.
   2182         if (!inQuote && isSyntaxChar(ch)) {
   2183             int32_t fieldPat = i;
   2184 
   2185             // Count the length of this field specifier
   2186             count = 1;
   2187             while ((i+1)<fPattern.length() &&
   2188                    fPattern.charAt(i+1) == ch) {
   2189                 ++count;
   2190                 ++i;
   2191             }
   2192 
   2193             if (isNumeric(ch, count)) {
   2194                 if (abutPat < 0) {
   2195                     // Determine if there is an abutting numeric field.
   2196                     // Record the start of a set of abutting numeric fields.
   2197                     if (isAtNumericField(fPattern, i + 1)) {
   2198                         abutPat = fieldPat;
   2199                         abutStart = pos;
   2200                         abutPass = 0;
   2201                     }
   2202                 }
   2203             } else {
   2204                 abutPat = -1; // End of any abutting fields
   2205             }
   2206 
   2207             // Handle fields within a run of abutting numeric fields.  Take
   2208             // the pattern "HHmmss" as an example. We will try to parse
   2209             // 2/2/2 characters of the input text, then if that fails,
   2210             // 1/2/2.  We only adjust the width of the leftmost field; the
   2211             // others remain fixed.  This allows "123456" => 12:34:56, but
   2212             // "12345" => 1:23:45.  Likewise, for the pattern "yyyyMMdd" we
   2213             // try 4/2/2, 3/2/2, 2/2/2, and finally 1/2/2.
   2214             if (abutPat >= 0) {
   2215                 // If we are at the start of a run of abutting fields, then
   2216                 // shorten this field in each pass.  If we can't shorten
   2217                 // this field any more, then the parse of this set of
   2218                 // abutting numeric fields has failed.
   2219                 if (fieldPat == abutPat) {
   2220                     count -= abutPass++;
   2221                     if (count == 0) {
   2222                         status = U_PARSE_ERROR;
   2223                         goto ExitParse;
   2224                     }
   2225                 }
   2226 
   2227                 pos = subParse(text, pos, ch, count,
   2228                                TRUE, FALSE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType, mutableNFs);
   2229 
   2230                 // If the parse fails anywhere in the run, back up to the
   2231                 // start of the run and retry.
   2232                 if (pos < 0) {
   2233                     i = abutPat - 1;
   2234                     pos = abutStart;
   2235                     continue;
   2236                 }
   2237             }
   2238 
   2239             // Handle non-numeric fields and non-abutting numeric
   2240             // fields.
   2241             else if (ch != 0x6C) { // pattern char 'l' (SMALL LETTER L) just gets ignored
   2242                 int32_t s = subParse(text, pos, ch, count,
   2243                                FALSE, TRUE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType, mutableNFs, &dayPeriodInt);
   2244 
   2245                 if (s == -pos-1) {
   2246                     // era not present, in special cases allow this to continue
   2247                     // from the position where the era was expected
   2248                     s = pos;
   2249 
   2250                     if (i+1 < fPattern.length()) {
   2251                         // move to next pattern character
   2252                         UChar ch = fPattern.charAt(i+1);
   2253 
   2254                         // check for whitespace
   2255                         if (PatternProps::isWhiteSpace(ch)) {
   2256                             i++;
   2257                             // Advance over run in pattern
   2258                             while ((i+1)<fPattern.length() &&
   2259                                    PatternProps::isWhiteSpace(fPattern.charAt(i+1))) {
   2260                                 ++i;
   2261                             }
   2262                         }
   2263                     }
   2264                 }
   2265                 else if (s <= 0) {
   2266                     status = U_PARSE_ERROR;
   2267                     goto ExitParse;
   2268                 }
   2269                 pos = s;
   2270             }
   2271         }
   2272 
   2273         // Handle literal pattern characters.  These are any
   2274         // quoted characters and non-alphabetic unquoted
   2275         // characters.
   2276         else {
   2277 
   2278             abutPat = -1; // End of any abutting fields
   2279 
   2280             if (! matchLiterals(fPattern, i, text, pos, getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status), getBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, status), isLenient())) {
   2281                 status = U_PARSE_ERROR;
   2282                 goto ExitParse;
   2283             }
   2284         }
   2285     }
   2286 
   2287     // Special hack for trailing "." after non-numeric field.
   2288     if (text.charAt(pos) == 0x2e && getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status)) {
   2289         // only do if the last field is not numeric
   2290         if (isAfterNonNumericField(fPattern, fPattern.length())) {
   2291             pos++; // skip the extra "."
   2292         }
   2293     }
   2294 
   2295     // If dayPeriod is set, use it in conjunction with hour-of-day to determine am/pm.
   2296     if (dayPeriodInt >= 0) {
   2297         DayPeriodRules::DayPeriod dayPeriod = (DayPeriodRules::DayPeriod)dayPeriodInt;
   2298         const DayPeriodRules *ruleSet = DayPeriodRules::getInstance(this->getSmpFmtLocale(), status);
   2299 
   2300         if (!cal.isSet(UCAL_HOUR) && !cal.isSet(UCAL_HOUR_OF_DAY)) {
   2301             // If hour is not set, set time to the midpoint of current day period, overwriting
   2302             // minutes if it's set.
   2303             double midPoint = ruleSet->getMidPointForDayPeriod(dayPeriod, status);
   2304 
   2305             // If we can't get midPoint we do nothing.
   2306             if (U_SUCCESS(status)) {
   2307                 // Truncate midPoint toward zero to get the hour.
   2308                 // Any leftover means it was a half-hour.
   2309                 int32_t midPointHour = (int32_t) midPoint;
   2310                 int32_t midPointMinute = (midPoint - midPointHour) > 0 ? 30 : 0;
   2311 
   2312                 // No need to set am/pm because hour-of-day is set last therefore takes precedence.
   2313                 cal.set(UCAL_HOUR_OF_DAY, midPointHour);
   2314                 cal.set(UCAL_MINUTE, midPointMinute);
   2315             }
   2316         } else {
   2317             int hourOfDay;
   2318 
   2319             if (cal.isSet(UCAL_HOUR_OF_DAY)) {  // Hour is parsed in 24-hour format.
   2320                 hourOfDay = cal.get(UCAL_HOUR_OF_DAY, status);
   2321             } else {  // Hour is parsed in 12-hour format.
   2322                 hourOfDay = cal.get(UCAL_HOUR, status);
   2323                 // cal.get() turns 12 to 0 for 12-hour time; change 0 to 12
   2324                 // so 0 unambiguously means a 24-hour time from above.
   2325                 if (hourOfDay == 0) { hourOfDay = 12; }
   2326             }
   2327             U_ASSERT(0 <= hourOfDay && hourOfDay <= 23);
   2328 
   2329 
   2330             // If hour-of-day is 0 or 13 thru 23 then input time in unambiguously in 24-hour format.
   2331             if (hourOfDay == 0 || (13 <= hourOfDay && hourOfDay <= 23)) {
   2332                 // Make hour-of-day take precedence over (hour + am/pm) by setting it again.
   2333                 cal.set(UCAL_HOUR_OF_DAY, hourOfDay);
   2334             } else {
   2335                 // We have a 12-hour time and need to choose between am and pm.
   2336                 // Behave as if dayPeriod spanned 6 hours each way from its center point.
   2337                 // This will parse correctly for consistent time + period (e.g. 10 at night) as
   2338                 // well as provide a reasonable recovery for inconsistent time + period (e.g.
   2339                 // 9 in the afternoon).
   2340 
   2341                 // Assume current time is in the AM.
   2342                 // - Change 12 back to 0 for easier handling of 12am.
   2343                 // - Append minutes as fractional hours because e.g. 8:15 and 8:45 could be parsed
   2344                 // into different half-days if center of dayPeriod is at 14:30.
   2345                 // - cal.get(MINUTE) will return 0 if MINUTE is unset, which works.
   2346                 if (hourOfDay == 12) { hourOfDay = 0; }
   2347                 double currentHour = hourOfDay + (cal.get(UCAL_MINUTE, status)) / 60.0;
   2348                 double midPointHour = ruleSet->getMidPointForDayPeriod(dayPeriod, status);
   2349 
   2350                 if (U_SUCCESS(status)) {
   2351                     double hoursAheadMidPoint = currentHour - midPointHour;
   2352 
   2353                     // Assume current time is in the AM.
   2354                     if (-6 <= hoursAheadMidPoint && hoursAheadMidPoint < 6) {
   2355                         // Assumption holds; set time as such.
   2356                         cal.set(UCAL_AM_PM, 0);
   2357                     } else {
   2358                         cal.set(UCAL_AM_PM, 1);
   2359                     }
   2360                 }
   2361             }
   2362         }
   2363     }
   2364 
   2365     // At this point the fields of Calendar have been set.  Calendar
   2366     // will fill in default values for missing fields when the time
   2367     // is computed.
   2368 
   2369     parsePos.setIndex(pos);
   2370 
   2371     // This part is a problem:  When we call parsedDate.after, we compute the time.
   2372     // Take the date April 3 2004 at 2:30 am.  When this is first set up, the year
   2373     // will be wrong if we're parsing a 2-digit year pattern.  It will be 1904.
   2374     // April 3 1904 is a Sunday (unlike 2004) so it is the DST onset day.  2:30 am
   2375     // is therefore an "impossible" time, since the time goes from 1:59 to 3:00 am
   2376     // on that day.  It is therefore parsed out to fields as 3:30 am.  Then we
   2377     // add 100 years, and get April 3 2004 at 3:30 am.  Note that April 3 2004 is
   2378     // a Saturday, so it can have a 2:30 am -- and it should. [LIU]
   2379     /*
   2380         UDate parsedDate = calendar.getTime();
   2381         if( ambiguousYear[0] && !parsedDate.after(fDefaultCenturyStart) ) {
   2382             calendar.add(Calendar.YEAR, 100);
   2383             parsedDate = calendar.getTime();
   2384         }
   2385     */
   2386     // Because of the above condition, save off the fields in case we need to readjust.
   2387     // The procedure we use here is not particularly efficient, but there is no other
   2388     // way to do this given the API restrictions present in Calendar.  We minimize
   2389     // inefficiency by only performing this computation when it might apply, that is,
   2390     // when the two-digit year is equal to the start year, and thus might fall at the
   2391     // front or the back of the default century.  This only works because we adjust
   2392     // the year correctly to start with in other cases -- see subParse().
   2393     if (ambiguousYear[0] || tzTimeType != UTZFMT_TIME_TYPE_UNKNOWN) // If this is true then the two-digit year == the default start year
   2394     {
   2395         // We need a copy of the fields, and we need to avoid triggering a call to
   2396         // complete(), which will recalculate the fields.  Since we can't access
   2397         // the fields[] array in Calendar, we clone the entire object.  This will
   2398         // stop working if Calendar.clone() is ever rewritten to call complete().
   2399         Calendar *copy;
   2400         if (ambiguousYear[0]) {
   2401             copy = cal.clone();
   2402             // Check for failed cloning.
   2403             if (copy == NULL) {
   2404                 status = U_MEMORY_ALLOCATION_ERROR;
   2405                 goto ExitParse;
   2406             }
   2407             UDate parsedDate = copy->getTime(status);
   2408             // {sfb} check internalGetDefaultCenturyStart
   2409             if (fHaveDefaultCentury && (parsedDate < fDefaultCenturyStart)) {
   2410                 // We can't use add here because that does a complete() first.
   2411                 cal.set(UCAL_YEAR, fDefaultCenturyStartYear + 100);
   2412             }
   2413             delete copy;
   2414         }
   2415 
   2416         if (tzTimeType != UTZFMT_TIME_TYPE_UNKNOWN) {
   2417             copy = cal.clone();
   2418             // Check for failed cloning.
   2419             if (copy == NULL) {
   2420                 status = U_MEMORY_ALLOCATION_ERROR;
   2421                 goto ExitParse;
   2422             }
   2423             const TimeZone & tz = cal.getTimeZone();
   2424             BasicTimeZone *btz = NULL;
   2425 
   2426             if (dynamic_cast<const OlsonTimeZone *>(&tz) != NULL
   2427                 || dynamic_cast<const SimpleTimeZone *>(&tz) != NULL
   2428                 || dynamic_cast<const RuleBasedTimeZone *>(&tz) != NULL
   2429                 || dynamic_cast<const VTimeZone *>(&tz) != NULL) {
   2430                 btz = (BasicTimeZone*)&tz;
   2431             }
   2432 
   2433             // Get local millis
   2434             copy->set(UCAL_ZONE_OFFSET, 0);
   2435             copy->set(UCAL_DST_OFFSET, 0);
   2436             UDate localMillis = copy->getTime(status);
   2437 
   2438             // Make sure parsed time zone type (Standard or Daylight)
   2439             // matches the rule used by the parsed time zone.
   2440             int32_t raw, dst;
   2441             if (btz != NULL) {
   2442                 if (tzTimeType == UTZFMT_TIME_TYPE_STANDARD) {
   2443                     btz->getOffsetFromLocal(localMillis,
   2444                         BasicTimeZone::kStandard, BasicTimeZone::kStandard, raw, dst, status);
   2445                 } else {
   2446                     btz->getOffsetFromLocal(localMillis,
   2447                         BasicTimeZone::kDaylight, BasicTimeZone::kDaylight, raw, dst, status);
   2448                 }
   2449             } else {
   2450                 // No good way to resolve ambiguous time at transition,
   2451                 // but following code work in most case.
   2452                 tz.getOffset(localMillis, TRUE, raw, dst, status);
   2453             }
   2454 
   2455             // Now, compare the results with parsed type, either standard or daylight saving time
   2456             int32_t resolvedSavings = dst;
   2457             if (tzTimeType == UTZFMT_TIME_TYPE_STANDARD) {
   2458                 if (dst != 0) {
   2459                     // Override DST_OFFSET = 0 in the result calendar
   2460                     resolvedSavings = 0;
   2461                 }
   2462             } else { // tztype == TZTYPE_DST
   2463                 if (dst == 0) {
   2464                     if (btz != NULL) {
   2465                         UDate time = localMillis + raw;
   2466                         // We use the nearest daylight saving time rule.
   2467                         TimeZoneTransition beforeTrs, afterTrs;
   2468                         UDate beforeT = time, afterT = time;
   2469                         int32_t beforeSav = 0, afterSav = 0;
   2470                         UBool beforeTrsAvail, afterTrsAvail;
   2471 
   2472                         // Search for DST rule before or on the time
   2473                         while (TRUE) {
   2474                             beforeTrsAvail = btz->getPreviousTransition(beforeT, TRUE, beforeTrs);
   2475                             if (!beforeTrsAvail) {
   2476                                 break;
   2477                             }
   2478                             beforeT = beforeTrs.getTime() - 1;
   2479                             beforeSav = beforeTrs.getFrom()->getDSTSavings();
   2480                             if (beforeSav != 0) {
   2481                                 break;
   2482                             }
   2483                         }
   2484 
   2485                         // Search for DST rule after the time
   2486                         while (TRUE) {
   2487                             afterTrsAvail = btz->getNextTransition(afterT, FALSE, afterTrs);
   2488                             if (!afterTrsAvail) {
   2489                                 break;
   2490                             }
   2491                             afterT = afterTrs.getTime();
   2492                             afterSav = afterTrs.getTo()->getDSTSavings();
   2493                             if (afterSav != 0) {
   2494                                 break;
   2495                             }
   2496                         }
   2497 
   2498                         if (beforeTrsAvail && afterTrsAvail) {
   2499                             if (time - beforeT > afterT - time) {
   2500                                 resolvedSavings = afterSav;
   2501                             } else {
   2502                                 resolvedSavings = beforeSav;
   2503                             }
   2504                         } else if (beforeTrsAvail && beforeSav != 0) {
   2505                             resolvedSavings = beforeSav;
   2506                         } else if (afterTrsAvail && afterSav != 0) {
   2507                             resolvedSavings = afterSav;
   2508                         } else {
   2509                             resolvedSavings = btz->getDSTSavings();
   2510                         }
   2511                     } else {
   2512                         resolvedSavings = tz.getDSTSavings();
   2513                     }
   2514                     if (resolvedSavings == 0) {
   2515                         // final fallback
   2516                         resolvedSavings = U_MILLIS_PER_HOUR;
   2517                     }
   2518                 }
   2519             }
   2520             cal.set(UCAL_ZONE_OFFSET, raw);
   2521             cal.set(UCAL_DST_OFFSET, resolvedSavings);
   2522             delete copy;
   2523         }
   2524     }
   2525 ExitParse:
   2526     // Set the parsed result if local calendar is used
   2527     // instead of the input calendar
   2528     if (U_SUCCESS(status) && workCal != &cal) {
   2529         cal.setTimeZone(workCal->getTimeZone());
   2530         cal.setTime(workCal->getTime(status), status);
   2531     }
   2532 
   2533     if (numericLeapMonthFormatter != NULL) {
   2534         delete numericLeapMonthFormatter;
   2535     }
   2536     if (calClone != NULL) {
   2537         delete calClone;
   2538     }
   2539 
   2540     // If any Calendar calls failed, we pretend that we
   2541     // couldn't parse the string, when in reality this isn't quite accurate--
   2542     // we did parse it; the Calendar calls just failed.
   2543     if (U_FAILURE(status)) {
   2544         parsePos.setErrorIndex(pos);
   2545         parsePos.setIndex(start);
   2546     }
   2547 }
   2548 
   2549 //----------------------------------------------------------------------
   2550 
   2551 static int32_t
   2552 matchStringWithOptionalDot(const UnicodeString &text,
   2553                             int32_t index,
   2554                             const UnicodeString &data);
   2555 
   2556 int32_t SimpleDateFormat::matchQuarterString(const UnicodeString& text,
   2557                               int32_t start,
   2558                               UCalendarDateFields field,
   2559                               const UnicodeString* data,
   2560                               int32_t dataCount,
   2561                               Calendar& cal) const
   2562 {
   2563     int32_t i = 0;
   2564     int32_t count = dataCount;
   2565 
   2566     // There may be multiple strings in the data[] array which begin with
   2567     // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech).
   2568     // We keep track of the longest match, and return that.  Note that this
   2569     // unfortunately requires us to test all array elements.
   2570     int32_t bestMatchLength = 0, bestMatch = -1;
   2571     UnicodeString bestMatchName;
   2572 
   2573     for (; i < count; ++i) {
   2574         int32_t matchLength = 0;
   2575         if ((matchLength = matchStringWithOptionalDot(text, start, data[i])) > bestMatchLength) {
   2576             bestMatchLength = matchLength;
   2577             bestMatch = i;
   2578         }
   2579     }
   2580 
   2581     if (bestMatch >= 0) {
   2582         cal.set(field, bestMatch * 3);
   2583         return start + bestMatchLength;
   2584     }
   2585 
   2586     return -start;
   2587 }
   2588 
   2589 int32_t SimpleDateFormat::matchDayPeriodStrings(const UnicodeString& text, int32_t start,
   2590                               const UnicodeString* data, int32_t dataCount,
   2591                               int32_t &dayPeriod) const
   2592 {
   2593 
   2594     int32_t bestMatchLength = 0, bestMatch = -1;
   2595 
   2596     for (int32_t i = 0; i < dataCount; ++i) {
   2597         int32_t matchLength = 0;
   2598         if ((matchLength = matchStringWithOptionalDot(text, start, data[i])) > bestMatchLength) {
   2599             bestMatchLength = matchLength;
   2600             bestMatch = i;
   2601         }
   2602     }
   2603 
   2604     if (bestMatch >= 0) {
   2605         dayPeriod = bestMatch;
   2606         return start + bestMatchLength;
   2607     }
   2608 
   2609     return -start;
   2610 }
   2611 
   2612 //----------------------------------------------------------------------
   2613 UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
   2614                                       int32_t &patternOffset,
   2615                                       const UnicodeString &text,
   2616                                       int32_t &textOffset,
   2617                                       UBool whitespaceLenient,
   2618                                       UBool partialMatchLenient,
   2619                                       UBool oldLeniency)
   2620 {
   2621     UBool inQuote = FALSE;
   2622     UnicodeString literal;
   2623     int32_t i = patternOffset;
   2624 
   2625     // scan pattern looking for contiguous literal characters
   2626     for ( ; i < pattern.length(); i += 1) {
   2627         UChar ch = pattern.charAt(i);
   2628 
   2629         if (!inQuote && isSyntaxChar(ch)) {
   2630             break;
   2631         }
   2632 
   2633         if (ch == QUOTE) {
   2634             // Match a quote literal ('') inside OR outside of quotes
   2635             if ((i + 1) < pattern.length() && pattern.charAt(i + 1) == QUOTE) {
   2636                 i += 1;
   2637             } else {
   2638                 inQuote = !inQuote;
   2639                 continue;
   2640             }
   2641         }
   2642 
   2643         literal += ch;
   2644     }
   2645 
   2646     // at this point, literal contains the literal text
   2647     // and i is the index of the next non-literal pattern character.
   2648     int32_t p;
   2649     int32_t t = textOffset;
   2650 
   2651     if (whitespaceLenient) {
   2652         // trim leading, trailing whitespace from
   2653         // the literal text
   2654         literal.trim();
   2655 
   2656         // ignore any leading whitespace in the text
   2657         while (t < text.length() && u_isWhitespace(text.charAt(t))) {
   2658             t += 1;
   2659         }
   2660     }
   2661 
   2662     for (p = 0; p < literal.length() && t < text.length();) {
   2663         UBool needWhitespace = FALSE;
   2664 
   2665         while (p < literal.length() && PatternProps::isWhiteSpace(literal.charAt(p))) {
   2666             needWhitespace = TRUE;
   2667             p += 1;
   2668         }
   2669 
   2670         if (needWhitespace) {
   2671             int32_t tStart = t;
   2672 
   2673             while (t < text.length()) {
   2674                 UChar tch = text.charAt(t);
   2675 
   2676                 if (!u_isUWhiteSpace(tch) && !PatternProps::isWhiteSpace(tch)) {
   2677                     break;
   2678                 }
   2679 
   2680                 t += 1;
   2681             }
   2682 
   2683             // TODO: should we require internal spaces
   2684             // in lenient mode? (There won't be any
   2685             // leading or trailing spaces)
   2686             if (!whitespaceLenient && t == tStart) {
   2687                 // didn't find matching whitespace:
   2688                 // an error in strict mode
   2689                 return FALSE;
   2690             }
   2691 
   2692             // In strict mode, this run of whitespace
   2693             // may have been at the end.
   2694             if (p >= literal.length()) {
   2695                 break;
   2696             }
   2697         }
   2698         if (t >= text.length() || literal.charAt(p) != text.charAt(t)) {
   2699             // Ran out of text, or found a non-matching character:
   2700             // OK in lenient mode, an error in strict mode.
   2701             if (whitespaceLenient) {
   2702                 if (t == textOffset && text.charAt(t) == 0x2e &&
   2703                         isAfterNonNumericField(pattern, patternOffset)) {
   2704                     // Lenient mode and the literal input text begins with a "." and
   2705                     // we are after a non-numeric field: We skip the "."
   2706                     ++t;
   2707                     continue;  // Do not update p.
   2708                 }
   2709                 // if it is actual whitespace and we're whitespace lenient it's OK
   2710 
   2711                 UChar wsc = text.charAt(t);
   2712                 if(PatternProps::isWhiteSpace(wsc)) {
   2713                     // Lenient mode and it's just whitespace we skip it
   2714                     ++t;
   2715                     continue;  // Do not update p.
   2716                 }
   2717             }
   2718             // hack around oldleniency being a bit of a catch-all bucket and we're just adding support specifically for paritial matches
   2719             if(partialMatchLenient && oldLeniency) {
   2720                 break;
   2721             }
   2722 
   2723             return FALSE;
   2724         }
   2725         ++p;
   2726         ++t;
   2727     }
   2728 
   2729     // At this point if we're in strict mode we have a complete match.
   2730     // If we're in lenient mode we may have a partial match, or no
   2731     // match at all.
   2732     if (p <= 0) {
   2733         // no match. Pretend it matched a run of whitespace
   2734         // and ignorables in the text.
   2735         const  UnicodeSet *ignorables = NULL;
   2736         UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(pattern.charAt(i));
   2737         if (patternCharIndex != UDAT_FIELD_COUNT) {
   2738             ignorables = SimpleDateFormatStaticSets::getIgnorables(patternCharIndex);
   2739         }
   2740 
   2741         for (t = textOffset; t < text.length(); t += 1) {
   2742             UChar ch = text.charAt(t);
   2743 
   2744             if (ignorables == NULL || !ignorables->contains(ch)) {
   2745                 break;
   2746             }
   2747         }
   2748     }
   2749 
   2750     // if we get here, we've got a complete match.
   2751     patternOffset = i - 1;
   2752     textOffset = t;
   2753 
   2754     return TRUE;
   2755 }
   2756 
   2757 //----------------------------------------------------------------------
   2758 
   2759 int32_t SimpleDateFormat::matchString(const UnicodeString& text,
   2760                               int32_t start,
   2761                               UCalendarDateFields field,
   2762                               const UnicodeString* data,
   2763                               int32_t dataCount,
   2764                               const UnicodeString* monthPattern,
   2765                               Calendar& cal) const
   2766 {
   2767     int32_t i = 0;
   2768     int32_t count = dataCount;
   2769 
   2770     if (field == UCAL_DAY_OF_WEEK) i = 1;
   2771 
   2772     // There may be multiple strings in the data[] array which begin with
   2773     // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech).
   2774     // We keep track of the longest match, and return that.  Note that this
   2775     // unfortunately requires us to test all array elements.
   2776     int32_t bestMatchLength = 0, bestMatch = -1;
   2777     UnicodeString bestMatchName;
   2778     int32_t isLeapMonth = 0;
   2779 
   2780     for (; i < count; ++i) {
   2781         int32_t matchLen = 0;
   2782         if ((matchLen = matchStringWithOptionalDot(text, start, data[i])) > bestMatchLength) {
   2783             bestMatch = i;
   2784             bestMatchLength = matchLen;
   2785         }
   2786 
   2787         if (monthPattern != NULL) {
   2788             UErrorCode status = U_ZERO_ERROR;
   2789             UnicodeString leapMonthName;
   2790             SimpleFormatter(*monthPattern, 1, 1, status).format(data[i], leapMonthName, status);
   2791             if (U_SUCCESS(status)) {
   2792                 if ((matchLen = matchStringWithOptionalDot(text, start, leapMonthName)) > bestMatchLength) {
   2793                     bestMatch = i;
   2794                     bestMatchLength = matchLen;
   2795                     isLeapMonth = 1;
   2796                 }
   2797             }
   2798         }
   2799     }
   2800 
   2801     if (bestMatch >= 0) {
   2802         if (field < UCAL_FIELD_COUNT) {
   2803             // Adjustment for Hebrew Calendar month Adar II
   2804             if (!strcmp(cal.getType(),"hebrew") && field==UCAL_MONTH && bestMatch==13) {
   2805                 cal.set(field,6);
   2806             } else {
   2807                 if (field == UCAL_YEAR) {
   2808                     bestMatch++; // only get here for cyclic year names, which match 1-based years 1-60
   2809                 }
   2810                 cal.set(field, bestMatch);
   2811             }
   2812             if (monthPattern != NULL) {
   2813                 cal.set(UCAL_IS_LEAP_MONTH, isLeapMonth);
   2814             }
   2815         }
   2816 
   2817         return start + bestMatchLength;
   2818     }
   2819 
   2820     return -start;
   2821 }
   2822 
   2823 static int32_t
   2824 matchStringWithOptionalDot(const UnicodeString &text,
   2825                             int32_t index,
   2826                             const UnicodeString &data) {
   2827     UErrorCode sts = U_ZERO_ERROR;
   2828     int32_t matchLenText = 0;
   2829     int32_t matchLenData = 0;
   2830 
   2831     u_caseInsensitivePrefixMatch(text.getBuffer() + index, text.length() - index,
   2832                                  data.getBuffer(), data.length(),
   2833                                  0 /* default case option */,
   2834                                  &matchLenText, &matchLenData,
   2835                                  &sts);
   2836     U_ASSERT (U_SUCCESS(sts));
   2837 
   2838     if (matchLenData == data.length() /* normal match */
   2839         || (data.charAt(data.length() - 1) == 0x2e
   2840             && matchLenData == data.length() - 1 /* match without trailing dot */)) {
   2841         return matchLenText;
   2842     }
   2843 
   2844     return 0;
   2845 }
   2846 
   2847 //----------------------------------------------------------------------
   2848 
   2849 void
   2850 SimpleDateFormat::set2DigitYearStart(UDate d, UErrorCode& status)
   2851 {
   2852     parseAmbiguousDatesAsAfter(d, status);
   2853 }
   2854 
   2855 /**
   2856  * Private member function that converts the parsed date strings into
   2857  * timeFields. Returns -start (for ParsePosition) if failed.
   2858  */
   2859 int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UChar ch, int32_t count,
   2860                            UBool obeyCount, UBool allowNegative, UBool ambiguousYear[], int32_t& saveHebrewMonth, Calendar& cal,
   2861                            int32_t patLoc, MessageFormat * numericLeapMonthFormatter, UTimeZoneFormatTimeType *tzTimeType, SimpleDateFormatMutableNFs &mutableNFs,
   2862                            int32_t *dayPeriod) const
   2863 {
   2864     Formattable number;
   2865     int32_t value = 0;
   2866     int32_t i;
   2867     int32_t ps = 0;
   2868     UErrorCode status = U_ZERO_ERROR;
   2869     ParsePosition pos(0);
   2870     UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(ch);
   2871     NumberFormat *currentNumberFormat;
   2872     UnicodeString temp;
   2873     UBool gotNumber = FALSE;
   2874 
   2875 #if defined (U_DEBUG_CAL)
   2876     //fprintf(stderr, "%s:%d - [%c]  st=%d \n", __FILE__, __LINE__, (char) ch, start);
   2877 #endif
   2878 
   2879     if (patternCharIndex == UDAT_FIELD_COUNT) {
   2880         return -start;
   2881     }
   2882 
   2883     currentNumberFormat = mutableNFs.get(getNumberFormatByIndex(patternCharIndex));
   2884     if (currentNumberFormat == NULL) {
   2885         return -start;
   2886     }
   2887     UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex]; // UCAL_FIELD_COUNT if irrelevant
   2888     UnicodeString hebr("hebr", 4, US_INV);
   2889 
   2890     if (numericLeapMonthFormatter != NULL) {
   2891         numericLeapMonthFormatter->setFormats((const Format **)&currentNumberFormat, 1);
   2892     }
   2893     UBool isChineseCalendar = (uprv_strcmp(cal.getType(),"chinese") == 0 || uprv_strcmp(cal.getType(),"dangi") == 0);
   2894 
   2895     // If there are any spaces here, skip over them.  If we hit the end
   2896     // of the string, then fail.
   2897     for (;;) {
   2898         if (start >= text.length()) {
   2899             return -start;
   2900         }
   2901         UChar32 c = text.char32At(start);
   2902         if (!u_isUWhiteSpace(c) /*||*/ && !PatternProps::isWhiteSpace(c)) {
   2903             break;
   2904         }
   2905         start += U16_LENGTH(c);
   2906     }
   2907     pos.setIndex(start);
   2908 
   2909     // We handle a few special cases here where we need to parse
   2910     // a number value.  We handle further, more generic cases below.  We need
   2911     // to handle some of them here because some fields require extra processing on
   2912     // the parsed value.
   2913     if (patternCharIndex == UDAT_HOUR_OF_DAY1_FIELD ||                       // k
   2914         patternCharIndex == UDAT_HOUR_OF_DAY0_FIELD ||                       // H
   2915         patternCharIndex == UDAT_HOUR1_FIELD ||                              // h
   2916         patternCharIndex == UDAT_HOUR0_FIELD ||                              // K
   2917         (patternCharIndex == UDAT_DOW_LOCAL_FIELD && count <= 2) ||          // e
   2918         (patternCharIndex == UDAT_STANDALONE_DAY_FIELD && count <= 2) ||     // c
   2919         (patternCharIndex == UDAT_MONTH_FIELD && count <= 2) ||              // M
   2920         (patternCharIndex == UDAT_STANDALONE_MONTH_FIELD && count <= 2) ||   // L
   2921         (patternCharIndex == UDAT_QUARTER_FIELD && count <= 2) ||            // Q
   2922         (patternCharIndex == UDAT_STANDALONE_QUARTER_FIELD && count <= 2) || // q
   2923         patternCharIndex == UDAT_YEAR_FIELD ||                               // y
   2924         patternCharIndex == UDAT_YEAR_WOY_FIELD ||                           // Y
   2925         patternCharIndex == UDAT_YEAR_NAME_FIELD ||                          // U (falls back to numeric)
   2926         (patternCharIndex == UDAT_ERA_FIELD && isChineseCalendar) ||         // G
   2927         patternCharIndex == UDAT_FRACTIONAL_SECOND_FIELD)                    // S
   2928     {
   2929         int32_t parseStart = pos.getIndex();
   2930         // It would be good to unify this with the obeyCount logic below,
   2931         // but that's going to be difficult.
   2932         const UnicodeString* src;
   2933 
   2934         UBool parsedNumericLeapMonth = FALSE;
   2935         if (numericLeapMonthFormatter != NULL && (patternCharIndex == UDAT_MONTH_FIELD || patternCharIndex == UDAT_STANDALONE_MONTH_FIELD)) {
   2936             int32_t argCount;
   2937             Formattable * args = numericLeapMonthFormatter->parse(text, pos, argCount);
   2938             if (args != NULL && argCount == 1 && pos.getIndex() > parseStart && args[0].isNumeric()) {
   2939                 parsedNumericLeapMonth = TRUE;
   2940                 number.setLong(args[0].getLong());
   2941                 cal.set(UCAL_IS_LEAP_MONTH, 1);
   2942                 delete[] args;
   2943             } else {
   2944                 pos.setIndex(parseStart);
   2945                 cal.set(UCAL_IS_LEAP_MONTH, 0);
   2946             }
   2947         }
   2948 
   2949         if (!parsedNumericLeapMonth) {
   2950             if (obeyCount) {
   2951                 if ((start+count) > text.length()) {
   2952                     return -start;
   2953                 }
   2954 
   2955                 text.extractBetween(0, start + count, temp);
   2956                 src = &temp;
   2957             } else {
   2958                 src = &text;
   2959             }
   2960 
   2961             parseInt(*src, number, pos, allowNegative,currentNumberFormat);
   2962         }
   2963 
   2964         int32_t txtLoc = pos.getIndex();
   2965 
   2966         if (txtLoc > parseStart) {
   2967             value = number.getLong();
   2968             gotNumber = TRUE;
   2969 
   2970             // suffix processing
   2971             if (value < 0 ) {
   2972                 txtLoc = checkIntSuffix(text, txtLoc, patLoc+1, TRUE);
   2973                 if (txtLoc != pos.getIndex()) {
   2974                     value *= -1;
   2975                 }
   2976             }
   2977             else {
   2978                 txtLoc = checkIntSuffix(text, txtLoc, patLoc+1, FALSE);
   2979             }
   2980 
   2981             if (!getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status)) {
   2982                 // Check the range of the value
   2983                 int32_t bias = gFieldRangeBias[patternCharIndex];
   2984                 if (bias >= 0 && (value > cal.getMaximum(field) + bias || value < cal.getMinimum(field) + bias)) {
   2985                     return -start;
   2986                 }
   2987             }
   2988 
   2989             pos.setIndex(txtLoc);
   2990         }
   2991     }
   2992 
   2993     // Make sure that we got a number if
   2994     // we want one, and didn't get one
   2995     // if we don't want one.
   2996     switch (patternCharIndex) {
   2997         case UDAT_HOUR_OF_DAY1_FIELD:
   2998         case UDAT_HOUR_OF_DAY0_FIELD:
   2999         case UDAT_HOUR1_FIELD:
   3000         case UDAT_HOUR0_FIELD:
   3001             // special range check for hours:
   3002             if (value < 0 || value > 24) {
   3003                 return -start;
   3004             }
   3005 
   3006             // fall through to gotNumber check
   3007             U_FALLTHROUGH;
   3008         case UDAT_YEAR_FIELD:
   3009         case UDAT_YEAR_WOY_FIELD:
   3010         case UDAT_FRACTIONAL_SECOND_FIELD:
   3011             // these must be a number
   3012             if (! gotNumber) {
   3013                 return -start;
   3014             }
   3015 
   3016             break;
   3017 
   3018         default:
   3019             // we check the rest of the fields below.
   3020             break;
   3021     }
   3022 
   3023     switch (patternCharIndex) {
   3024     case UDAT_ERA_FIELD:
   3025         if (isChineseCalendar) {
   3026             if (!gotNumber) {
   3027                 return -start;
   3028             }
   3029             cal.set(UCAL_ERA, value);
   3030             return pos.getIndex();
   3031         }
   3032         if (count == 5) {
   3033             ps = matchString(text, start, UCAL_ERA, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount, NULL, cal);
   3034         } else if (count == 4) {
   3035             ps = matchString(text, start, UCAL_ERA, fSymbols->fEraNames, fSymbols->fEraNamesCount, NULL, cal);
   3036         } else {
   3037             ps = matchString(text, start, UCAL_ERA, fSymbols->fEras, fSymbols->fErasCount, NULL, cal);
   3038         }
   3039 
   3040         // check return position, if it equals -start, then matchString error
   3041         // special case the return code so we don't necessarily fail out until we
   3042         // verify no year information also
   3043         if (ps == -start)
   3044             ps--;
   3045 
   3046         return ps;
   3047 
   3048     case UDAT_YEAR_FIELD:
   3049         // If there are 3 or more YEAR pattern characters, this indicates
   3050         // that the year value is to be treated literally, without any
   3051         // two-digit year adjustments (e.g., from "01" to 2001).  Otherwise
   3052         // we made adjustments to place the 2-digit year in the proper
   3053         // century, for parsed strings from "00" to "99".  Any other string
   3054         // is treated literally:  "2250", "-1", "1", "002".
   3055         if (fDateOverride.compare(hebr)==0 && value < 1000) {
   3056             value += HEBREW_CAL_CUR_MILLENIUM_START_YEAR;
   3057         } else if (text.moveIndex32(start, 2) == pos.getIndex() && !isChineseCalendar
   3058             && u_isdigit(text.char32At(start))
   3059             && u_isdigit(text.char32At(text.moveIndex32(start, 1))))
   3060         {
   3061             // only adjust year for patterns less than 3.
   3062             if(count < 3) {
   3063                 // Assume for example that the defaultCenturyStart is 6/18/1903.
   3064                 // This means that two-digit years will be forced into the range
   3065                 // 6/18/1903 to 6/17/2003.  As a result, years 00, 01, and 02
   3066                 // correspond to 2000, 2001, and 2002.  Years 04, 05, etc. correspond
   3067                 // to 1904, 1905, etc.  If the year is 03, then it is 2003 if the
   3068                 // other fields specify a date before 6/18, or 1903 if they specify a
   3069                 // date afterwards.  As a result, 03 is an ambiguous year.  All other
   3070                 // two-digit years are unambiguous.
   3071                 if(fHaveDefaultCentury) { // check if this formatter even has a pivot year
   3072                     int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100;
   3073                     ambiguousYear[0] = (value == ambiguousTwoDigitYear);
   3074                     value += (fDefaultCenturyStartYear/100)*100 +
   3075                             (value < ambiguousTwoDigitYear ? 100 : 0);
   3076                 }
   3077             }
   3078         }
   3079         cal.set(UCAL_YEAR, value);
   3080 
   3081         // Delayed checking for adjustment of Hebrew month numbers in non-leap years.
   3082         if (saveHebrewMonth >= 0) {
   3083             HebrewCalendar *hc = (HebrewCalendar*)&cal;
   3084             if (!hc->isLeapYear(value) && saveHebrewMonth >= 6) {
   3085                cal.set(UCAL_MONTH,saveHebrewMonth);
   3086             } else {
   3087                cal.set(UCAL_MONTH,saveHebrewMonth-1);
   3088             }
   3089             saveHebrewMonth = -1;
   3090         }
   3091         return pos.getIndex();
   3092 
   3093     case UDAT_YEAR_WOY_FIELD:
   3094         // Comment is the same as for UDAT_Year_FIELDs - look above
   3095         if (fDateOverride.compare(hebr)==0 && value < 1000) {
   3096             value += HEBREW_CAL_CUR_MILLENIUM_START_YEAR;
   3097         } else if (text.moveIndex32(start, 2) == pos.getIndex()
   3098             && u_isdigit(text.char32At(start))
   3099             && u_isdigit(text.char32At(text.moveIndex32(start, 1)))
   3100             && fHaveDefaultCentury )
   3101         {
   3102             int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100;
   3103             ambiguousYear[0] = (value == ambiguousTwoDigitYear);
   3104             value += (fDefaultCenturyStartYear/100)*100 +
   3105                 (value < ambiguousTwoDigitYear ? 100 : 0);
   3106         }
   3107         cal.set(UCAL_YEAR_WOY, value);
   3108         return pos.getIndex();
   3109 
   3110     case UDAT_YEAR_NAME_FIELD:
   3111         if (fSymbols->fShortYearNames != NULL) {
   3112             int32_t newStart = matchString(text, start, UCAL_YEAR, fSymbols->fShortYearNames, fSymbols->fShortYearNamesCount, NULL, cal);
   3113             if (newStart > 0) {
   3114                 return newStart;
   3115             }
   3116         }
   3117         if (gotNumber && (getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC,status) || value > fSymbols->fShortYearNamesCount)) {
   3118             cal.set(UCAL_YEAR, value);
   3119             return pos.getIndex();
   3120         }
   3121         return -start;
   3122 
   3123     case UDAT_MONTH_FIELD:
   3124     case UDAT_STANDALONE_MONTH_FIELD:
   3125         if (gotNumber) // i.e., M or MM.
   3126         {
   3127             // When parsing month numbers from the Hebrew Calendar, we might need to adjust the month depending on whether
   3128             // or not it was a leap year.  We may or may not yet know what year it is, so might have to delay checking until
   3129             // the year is parsed.
   3130             if (!strcmp(cal.getType(),"hebrew")) {
   3131                 HebrewCalendar *hc = (HebrewCalendar*)&cal;
   3132                 if (cal.isSet(UCAL_YEAR)) {
   3133                    UErrorCode status = U_ZERO_ERROR;
   3134                    if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6) {
   3135                        cal.set(UCAL_MONTH, value);
   3136                    } else {
   3137                        cal.set(UCAL_MONTH, value - 1);
   3138                    }
   3139                 } else {
   3140                     saveHebrewMonth = value;
   3141                 }
   3142             } else {
   3143                 // Don't want to parse the month if it is a string
   3144                 // while pattern uses numeric style: M/MM, L/LL
   3145                 // [We computed 'value' above.]
   3146                 cal.set(UCAL_MONTH, value - 1);
   3147             }
   3148             return pos.getIndex();
   3149         } else {
   3150             // count >= 3 // i.e., MMM/MMMM, LLL/LLLL
   3151             // Want to be able to parse both short and long forms.
   3152             // Try count == 4 first:
   3153             UnicodeString * wideMonthPat = NULL;
   3154             UnicodeString * shortMonthPat = NULL;
   3155             if (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount) {
   3156                 if (patternCharIndex==UDAT_MONTH_FIELD) {
   3157                     wideMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatWide];
   3158                     shortMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatAbbrev];
   3159                 } else {
   3160                     wideMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneWide];
   3161                     shortMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneAbbrev];
   3162                 }
   3163             }
   3164             int32_t newStart = 0;
   3165             if (patternCharIndex==UDAT_MONTH_FIELD) {
   3166                 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
   3167                     newStart = matchString(text, start, UCAL_MONTH, fSymbols->fMonths, fSymbols->fMonthsCount, wideMonthPat, cal); // try MMMM
   3168                     if (newStart > 0) {
   3169                         return newStart;
   3170                     }
   3171                 }
   3172                 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
   3173                     newStart = matchString(text, start, UCAL_MONTH, fSymbols->fShortMonths, fSymbols->fShortMonthsCount, shortMonthPat, cal); // try MMM
   3174                 }
   3175             } else {
   3176                 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
   3177                     newStart = matchString(text, start, UCAL_MONTH, fSymbols->fStandaloneMonths, fSymbols->fStandaloneMonthsCount, wideMonthPat, cal); // try LLLL
   3178                     if (newStart > 0) {
   3179                         return newStart;
   3180                     }
   3181                 }
   3182                 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
   3183                     newStart = matchString(text, start, UCAL_MONTH, fSymbols->fStandaloneShortMonths, fSymbols->fStandaloneShortMonthsCount, shortMonthPat, cal); // try LLL
   3184                 }
   3185             }
   3186             if (newStart > 0 || !getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status))  // currently we do not try to parse MMMMM/LLLLL: #8860
   3187                 return newStart;
   3188             // else we allowing parsing as number, below
   3189         }
   3190         break;
   3191 
   3192     case UDAT_HOUR_OF_DAY1_FIELD:
   3193         // [We computed 'value' above.]
   3194         if (value == cal.getMaximum(UCAL_HOUR_OF_DAY) + 1)
   3195             value = 0;
   3196 
   3197         // fall through to set field
   3198         U_FALLTHROUGH;
   3199     case UDAT_HOUR_OF_DAY0_FIELD:
   3200         cal.set(UCAL_HOUR_OF_DAY, value);
   3201         return pos.getIndex();
   3202 
   3203     case UDAT_FRACTIONAL_SECOND_FIELD:
   3204         // Fractional seconds left-justify
   3205         i = countDigits(text, start, pos.getIndex());
   3206         if (i < 3) {
   3207             while (i < 3) {
   3208                 value *= 10;
   3209                 i++;
   3210             }
   3211         } else {
   3212             int32_t a = 1;
   3213             while (i > 3) {
   3214                 a *= 10;
   3215                 i--;
   3216             }
   3217             value /= a;
   3218         }
   3219         cal.set(UCAL_MILLISECOND, value);
   3220         return pos.getIndex();
   3221 
   3222     case UDAT_DOW_LOCAL_FIELD:
   3223         if (gotNumber) // i.e., e or ee
   3224         {
   3225             // [We computed 'value' above.]
   3226             cal.set(UCAL_DOW_LOCAL, value);
   3227             return pos.getIndex();
   3228         }
   3229         // else for eee-eeeee fall through to handling of EEE-EEEEE
   3230         // fall through, do not break here
   3231         U_FALLTHROUGH;
   3232     case UDAT_DAY_OF_WEEK_FIELD:
   3233         {
   3234             // Want to be able to parse both short and long forms.
   3235             // Try count == 4 (EEEE) wide first:
   3236             int32_t newStart = 0;
   3237             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
   3238                 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
   3239                                           fSymbols->fWeekdays, fSymbols->fWeekdaysCount, NULL, cal)) > 0)
   3240                     return newStart;
   3241             }
   3242             // EEEE wide failed, now try EEE abbreviated
   3243             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
   3244                 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
   3245                                        fSymbols->fShortWeekdays, fSymbols->fShortWeekdaysCount, NULL, cal)) > 0)
   3246                     return newStart;
   3247             }
   3248             // EEE abbreviated failed, now try EEEEEE short
   3249             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 6) {
   3250                 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
   3251                                        fSymbols->fShorterWeekdays, fSymbols->fShorterWeekdaysCount, NULL, cal)) > 0)
   3252                     return newStart;
   3253             }
   3254             // EEEEEE short failed, now try EEEEE narrow
   3255             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 5) {
   3256                 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
   3257                                        fSymbols->fNarrowWeekdays, fSymbols->fNarrowWeekdaysCount, NULL, cal)) > 0)
   3258                     return newStart;
   3259             }
   3260             if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status) || patternCharIndex == UDAT_DAY_OF_WEEK_FIELD)
   3261                 return newStart;
   3262             // else we allowing parsing as number, below
   3263         }
   3264         break;
   3265 
   3266     case UDAT_STANDALONE_DAY_FIELD:
   3267         {
   3268             if (gotNumber) // c or cc
   3269             {
   3270                 // [We computed 'value' above.]
   3271                 cal.set(UCAL_DOW_LOCAL, value);
   3272                 return pos.getIndex();
   3273             }
   3274             // Want to be able to parse both short and long forms.
   3275             // Try count == 4 (cccc) first:
   3276             int32_t newStart = 0;
   3277             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
   3278                 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
   3279                                       fSymbols->fStandaloneWeekdays, fSymbols->fStandaloneWeekdaysCount, NULL, cal)) > 0)
   3280                     return newStart;
   3281             }
   3282             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
   3283                 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
   3284                                           fSymbols->fStandaloneShortWeekdays, fSymbols->fStandaloneShortWeekdaysCount, NULL, cal)) > 0)
   3285                     return newStart;
   3286             }
   3287             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 6) {
   3288                 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
   3289                                           fSymbols->fStandaloneShorterWeekdays, fSymbols->fStandaloneShorterWeekdaysCount, NULL, cal)) > 0)
   3290                     return newStart;
   3291             }
   3292             if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status))
   3293                 return newStart;
   3294             // else we allowing parsing as number, below
   3295         }
   3296         break;
   3297 
   3298     case UDAT_AM_PM_FIELD:
   3299         {
   3300             // optionally try both wide/abbrev and narrow forms
   3301             int32_t newStart = 0;
   3302             // try wide/abbrev
   3303             if( getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count < 5 ) {
   3304                 if ((newStart = matchString(text, start, UCAL_AM_PM, fSymbols->fAmPms, fSymbols->fAmPmsCount, NULL, cal)) > 0) {
   3305                     return newStart;
   3306                 }
   3307             }
   3308             // try narrow
   3309             if( getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count >= 5 ) {
   3310                 if ((newStart = matchString(text, start, UCAL_AM_PM, fSymbols->fNarrowAmPms, fSymbols->fNarrowAmPmsCount, NULL, cal)) > 0) {
   3311                     return newStart;
   3312                 }
   3313             }
   3314             // no matches for given options
   3315             return -start;
   3316         }
   3317 
   3318     case UDAT_HOUR1_FIELD:
   3319         // [We computed 'value' above.]
   3320         if (value == cal.getLeastMaximum(UCAL_HOUR)+1)
   3321             value = 0;
   3322 
   3323         // fall through to set field
   3324         U_FALLTHROUGH;
   3325     case UDAT_HOUR0_FIELD:
   3326         cal.set(UCAL_HOUR, value);
   3327         return pos.getIndex();
   3328 
   3329     case UDAT_QUARTER_FIELD:
   3330         if (gotNumber) // i.e., Q or QQ.
   3331         {
   3332             // Don't want to parse the month if it is a string
   3333             // while pattern uses numeric style: Q or QQ.
   3334             // [We computed 'value' above.]
   3335             cal.set(UCAL_MONTH, (value - 1) * 3);
   3336             return pos.getIndex();
   3337         } else {
   3338             // count >= 3 // i.e., QQQ or QQQQ
   3339             // Want to be able to parse both short and long forms.
   3340             // Try count == 4 first:
   3341             int32_t newStart = 0;
   3342 
   3343             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
   3344                 if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
   3345                                       fSymbols->fQuarters, fSymbols->fQuartersCount, cal)) > 0)
   3346                     return newStart;
   3347             }
   3348             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
   3349                 if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
   3350                                           fSymbols->fShortQuarters, fSymbols->fShortQuartersCount, cal)) > 0)
   3351                     return newStart;
   3352             }
   3353             if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status))
   3354                 return newStart;
   3355             // else we allowing parsing as number, below
   3356             if(!getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status))
   3357                 return -start;
   3358         }
   3359         break;
   3360 
   3361     case UDAT_STANDALONE_QUARTER_FIELD:
   3362         if (gotNumber) // i.e., q or qq.
   3363         {
   3364             // Don't want to parse the month if it is a string
   3365             // while pattern uses numeric style: q or q.
   3366             // [We computed 'value' above.]
   3367             cal.set(UCAL_MONTH, (value - 1) * 3);
   3368             return pos.getIndex();
   3369         } else {
   3370             // count >= 3 // i.e., qqq or qqqq
   3371             // Want to be able to parse both short and long forms.
   3372             // Try count == 4 first:
   3373             int32_t newStart = 0;
   3374 
   3375             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
   3376                 if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
   3377                                       fSymbols->fStandaloneQuarters, fSymbols->fStandaloneQuartersCount, cal)) > 0)
   3378                     return newStart;
   3379             }
   3380             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
   3381                 if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
   3382                                           fSymbols->fStandaloneShortQuarters, fSymbols->fStandaloneShortQuartersCount, cal)) > 0)
   3383                     return newStart;
   3384             }
   3385             if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status))
   3386                 return newStart;
   3387             // else we allowing parsing as number, below
   3388             if(!getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status))
   3389                 return -start;
   3390         }
   3391         break;
   3392 
   3393     case UDAT_TIMEZONE_FIELD: // 'z'
   3394         {
   3395             UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_SPECIFIC_SHORT : UTZFMT_STYLE_SPECIFIC_LONG;
   3396             TimeZone *tz  = tzFormat()->parse(style, text, pos, tzTimeType);
   3397             if (tz != NULL) {
   3398                 cal.adoptTimeZone(tz);
   3399                 return pos.getIndex();
   3400             }
   3401         }
   3402         break;
   3403     case UDAT_TIMEZONE_RFC_FIELD: // 'Z'
   3404         {
   3405             UTimeZoneFormatStyle style = (count < 4) ?
   3406                 UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL : ((count == 5) ? UTZFMT_STYLE_ISO_EXTENDED_FULL: UTZFMT_STYLE_LOCALIZED_GMT);
   3407             TimeZone *tz  = tzFormat()->parse(style, text, pos, tzTimeType);
   3408             if (tz != NULL) {
   3409                 cal.adoptTimeZone(tz);
   3410                 return pos.getIndex();
   3411             }
   3412             return -start;
   3413         }
   3414     case UDAT_TIMEZONE_GENERIC_FIELD: // 'v'
   3415         {
   3416             UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_GENERIC_SHORT : UTZFMT_STYLE_GENERIC_LONG;
   3417             TimeZone *tz  = tzFormat()->parse(style, text, pos, tzTimeType);
   3418             if (tz != NULL) {
   3419                 cal.adoptTimeZone(tz);
   3420                 return pos.getIndex();
   3421             }
   3422             return -start;
   3423         }
   3424     case UDAT_TIMEZONE_SPECIAL_FIELD: // 'V'
   3425         {
   3426             UTimeZoneFormatStyle style;
   3427             switch (count) {
   3428             case 1:
   3429                 style = UTZFMT_STYLE_ZONE_ID_SHORT;
   3430                 break;
   3431             case 2:
   3432                 style = UTZFMT_STYLE_ZONE_ID;
   3433                 break;
   3434             case 3:
   3435                 style = UTZFMT_STYLE_EXEMPLAR_LOCATION;
   3436                 break;
   3437             default:
   3438                 style = UTZFMT_STYLE_GENERIC_LOCATION;
   3439                 break;
   3440             }
   3441             TimeZone *tz  = tzFormat()->parse(style, text, pos, tzTimeType);
   3442             if (tz != NULL) {
   3443                 cal.adoptTimeZone(tz);
   3444                 return pos.getIndex();
   3445             }
   3446             return -start;
   3447         }
   3448     case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD: // 'O'
   3449         {
   3450             UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_LOCALIZED_GMT_SHORT : UTZFMT_STYLE_LOCALIZED_GMT;
   3451             TimeZone *tz  = tzFormat()->parse(style, text, pos, tzTimeType);
   3452             if (tz != NULL) {
   3453                 cal.adoptTimeZone(tz);
   3454                 return pos.getIndex();
   3455             }
   3456             return -start;
   3457         }
   3458     case UDAT_TIMEZONE_ISO_FIELD: // 'X'
   3459         {
   3460             UTimeZoneFormatStyle style;
   3461             switch (count) {
   3462             case 1:
   3463                 style = UTZFMT_STYLE_ISO_BASIC_SHORT;
   3464                 break;
   3465             case 2:
   3466                 style = UTZFMT_STYLE_ISO_BASIC_FIXED;
   3467                 break;
   3468             case 3:
   3469                 style = UTZFMT_STYLE_ISO_EXTENDED_FIXED;
   3470                 break;
   3471             case 4:
   3472                 style = UTZFMT_STYLE_ISO_BASIC_FULL;
   3473                 break;
   3474             default:
   3475                 style = UTZFMT_STYLE_ISO_EXTENDED_FULL;
   3476                 break;
   3477             }
   3478             TimeZone *tz  = tzFormat()->parse(style, text, pos, tzTimeType);
   3479             if (tz != NULL) {
   3480                 cal.adoptTimeZone(tz);
   3481                 return pos.getIndex();
   3482             }
   3483             return -start;
   3484         }
   3485     case UDAT_TIMEZONE_ISO_LOCAL_FIELD: // 'x'
   3486         {
   3487             UTimeZoneFormatStyle style;
   3488             switch (count) {
   3489             case 1:
   3490                 style = UTZFMT_STYLE_ISO_BASIC_LOCAL_SHORT;
   3491                 break;
   3492             case 2:
   3493                 style = UTZFMT_STYLE_ISO_BASIC_LOCAL_FIXED;
   3494                 break;
   3495             case 3:
   3496                 style = UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FIXED;
   3497                 break;
   3498             case 4:
   3499                 style = UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL;
   3500                 break;
   3501             default:
   3502                 style = UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL;
   3503                 break;
   3504             }
   3505             TimeZone *tz  = tzFormat()->parse(style, text, pos, tzTimeType);
   3506             if (tz != NULL) {
   3507                 cal.adoptTimeZone(tz);
   3508                 return pos.getIndex();
   3509             }
   3510             return -start;
   3511         }
   3512     // currently no pattern character is defined for UDAT_TIME_SEPARATOR_FIELD
   3513     // so we should not get here. Leave support in for future definition.
   3514     case UDAT_TIME_SEPARATOR_FIELD:
   3515         {
   3516             static const UChar def_sep = DateFormatSymbols::DEFAULT_TIME_SEPARATOR;
   3517             static const UChar alt_sep = DateFormatSymbols::ALTERNATE_TIME_SEPARATOR;
   3518 
   3519             // Try matching a time separator.
   3520             int32_t count = 1;
   3521             UnicodeString data[3];
   3522             fSymbols->getTimeSeparatorString(data[0]);
   3523 
   3524             // Add the default, if different from the locale.
   3525             if (data[0].compare(&def_sep, 1) != 0) {
   3526                 data[count++].setTo(def_sep);
   3527             }
   3528 
   3529             // If lenient, add also the alternate, if different from the locale.
   3530             if (isLenient() && data[0].compare(&alt_sep, 1) != 0) {
   3531                 data[count++].setTo(alt_sep);
   3532             }
   3533 
   3534             return matchString(text, start, UCAL_FIELD_COUNT /* => nothing to set */, data, count, NULL, cal);
   3535         }
   3536 
   3537     case UDAT_AM_PM_MIDNIGHT_NOON_FIELD:
   3538     {
   3539         U_ASSERT(dayPeriod != NULL);
   3540         int32_t ampmStart = subParse(text, start, 0x61, count,
   3541                            obeyCount, allowNegative, ambiguousYear, saveHebrewMonth, cal,
   3542                            patLoc, numericLeapMonthFormatter, tzTimeType, mutableNFs);
   3543 
   3544         if (ampmStart > 0) {
   3545             return ampmStart;
   3546         } else {
   3547             int32_t newStart = 0;
   3548 
   3549             // Only match the first two strings from the day period strings array.
   3550             if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
   3551                 if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fAbbreviatedDayPeriods,
   3552                                                         2, *dayPeriod)) > 0) {
   3553                     return newStart;
   3554                 }
   3555             }
   3556             if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 5) {
   3557                 if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fNarrowDayPeriods,
   3558                                                         2, *dayPeriod)) > 0) {
   3559                     return newStart;
   3560                 }
   3561             }
   3562             // count == 4, but allow other counts
   3563             if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status)) {
   3564                 if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fWideDayPeriods,
   3565                                                         2, *dayPeriod)) > 0) {
   3566                     return newStart;
   3567                 }
   3568             }
   3569 
   3570             return -start;
   3571         }
   3572     }
   3573 
   3574     case UDAT_FLEXIBLE_DAY_PERIOD_FIELD:
   3575     {
   3576         U_ASSERT(dayPeriod != NULL);
   3577         int32_t newStart = 0;
   3578 
   3579         if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
   3580             if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fAbbreviatedDayPeriods,
   3581                                 fSymbols->fAbbreviatedDayPeriodsCount, *dayPeriod)) > 0) {
   3582                 return newStart;
   3583             }
   3584         }
   3585         if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 5) {
   3586             if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fNarrowDayPeriods,
   3587                                 fSymbols->fNarrowDayPeriodsCount, *dayPeriod)) > 0) {
   3588                 return newStart;
   3589             }
   3590         }
   3591         if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
   3592             if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fWideDayPeriods,
   3593                                 fSymbols->fWideDayPeriodsCount, *dayPeriod)) > 0) {
   3594                 return newStart;
   3595             }
   3596         }
   3597 
   3598         return -start;
   3599     }
   3600 
   3601     default:
   3602         // Handle "generic" fields
   3603         // this is now handled below, outside the switch block
   3604         break;
   3605     }
   3606     // Handle "generic" fields:
   3607     // switch default case now handled here (outside switch block) to allow
   3608     // parsing of some string fields as digits for lenient case
   3609 
   3610     int32_t parseStart = pos.getIndex();
   3611     const UnicodeString* src;
   3612     if (obeyCount) {
   3613         if ((start+count) > text.length()) {
   3614             return -start;
   3615         }
   3616         text.extractBetween(0, start + count, temp);
   3617         src = &temp;
   3618     } else {
   3619         src = &text;
   3620     }
   3621     parseInt(*src, number, pos, allowNegative,currentNumberFormat);
   3622     if (pos.getIndex() != parseStart) {
   3623         int32_t value = number.getLong();
   3624 
   3625         // Don't need suffix processing here (as in number processing at the beginning of the function);
   3626         // the new fields being handled as numeric values (month, weekdays, quarters) should not have suffixes.
   3627 
   3628         if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status)) {
   3629             // Check the range of the value
   3630             int32_t bias = gFieldRangeBias[patternCharIndex];
   3631             if (bias >= 0 && (value > cal.getMaximum(field) + bias || value < cal.getMinimum(field) + bias)) {
   3632                 return -start;
   3633             }
   3634         }
   3635 
   3636         // For the following, need to repeat some of the "if (gotNumber)" code above:
   3637         // UDAT_[STANDALONE_]MONTH_FIELD, UDAT_DOW_LOCAL_FIELD, UDAT_STANDALONE_DAY_FIELD,
   3638         // UDAT_[STANDALONE_]QUARTER_FIELD
   3639         switch (patternCharIndex) {
   3640         case UDAT_MONTH_FIELD:
   3641             // See notes under UDAT_MONTH_FIELD case above
   3642             if (!strcmp(cal.getType(),"hebrew")) {
   3643                 HebrewCalendar *hc = (HebrewCalendar*)&cal;
   3644                 if (cal.isSet(UCAL_YEAR)) {
   3645                    UErrorCode status = U_ZERO_ERROR;
   3646                    if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6) {
   3647                        cal.set(UCAL_MONTH, value);
   3648                    } else {
   3649                        cal.set(UCAL_MONTH, value - 1);
   3650                    }
   3651                 } else {
   3652                     saveHebrewMonth = value;
   3653                 }
   3654             } else {
   3655                 cal.set(UCAL_MONTH, value - 1);
   3656             }
   3657             break;
   3658         case UDAT_STANDALONE_MONTH_FIELD:
   3659             cal.set(UCAL_MONTH, value - 1);
   3660             break;
   3661         case UDAT_DOW_LOCAL_FIELD:
   3662         case UDAT_STANDALONE_DAY_FIELD:
   3663             cal.set(UCAL_DOW_LOCAL, value);
   3664             break;
   3665         case UDAT_QUARTER_FIELD:
   3666         case UDAT_STANDALONE_QUARTER_FIELD:
   3667              cal.set(UCAL_MONTH, (value - 1) * 3);
   3668              break;
   3669         case UDAT_RELATED_YEAR_FIELD:
   3670             cal.setRelatedYear(value);
   3671             break;
   3672         default:
   3673             cal.set(field, value);
   3674             break;
   3675         }
   3676         return pos.getIndex();
   3677     }
   3678     return -start;
   3679 }
   3680 
   3681 /**
   3682  * Parse an integer using fNumberFormat.  This method is semantically
   3683  * const, but actually may modify fNumberFormat.
   3684  */
   3685 void SimpleDateFormat::parseInt(const UnicodeString& text,
   3686                                 Formattable& number,
   3687                                 ParsePosition& pos,
   3688                                 UBool allowNegative,
   3689                                 NumberFormat *fmt) const {
   3690     parseInt(text, number, -1, pos, allowNegative,fmt);
   3691 }
   3692 
   3693 /**
   3694  * Parse an integer using fNumberFormat up to maxDigits.
   3695  */
   3696 void SimpleDateFormat::parseInt(const UnicodeString& text,
   3697                                 Formattable& number,
   3698                                 int32_t maxDigits,
   3699                                 ParsePosition& pos,
   3700                                 UBool allowNegative,
   3701                                 NumberFormat *fmt) const {
   3702     UnicodeString oldPrefix;
   3703     DecimalFormat* df = NULL;
   3704     if (!allowNegative && (df = dynamic_cast<DecimalFormat*>(fmt)) != NULL) {
   3705         df->getNegativePrefix(oldPrefix);
   3706         df->setNegativePrefix(UnicodeString(TRUE, SUPPRESS_NEGATIVE_PREFIX, -1));
   3707     }
   3708     int32_t oldPos = pos.getIndex();
   3709     fmt->parse(text, number, pos);
   3710     if (df != NULL) {
   3711         df->setNegativePrefix(oldPrefix);
   3712     }
   3713 
   3714     if (maxDigits > 0) {
   3715         // adjust the result to fit into
   3716         // the maxDigits and move the position back
   3717         int32_t nDigits = pos.getIndex() - oldPos;
   3718         if (nDigits > maxDigits) {
   3719             int32_t val = number.getLong();
   3720             nDigits -= maxDigits;
   3721             while (nDigits > 0) {
   3722                 val /= 10;
   3723                 nDigits--;
   3724             }
   3725             pos.setIndex(oldPos + maxDigits);
   3726             number.setLong(val);
   3727         }
   3728     }
   3729 }
   3730 
   3731 int32_t SimpleDateFormat::countDigits(const UnicodeString& text, int32_t start, int32_t end) const {
   3732     int32_t numDigits = 0;
   3733     int32_t idx = start;
   3734     while (idx < end) {
   3735         UChar32 cp = text.char32At(idx);
   3736         if (u_isdigit(cp)) {
   3737             numDigits++;
   3738         }
   3739         idx += U16_LENGTH(cp);
   3740     }
   3741     return numDigits;
   3742 }
   3743 
   3744 //----------------------------------------------------------------------
   3745 
   3746 void SimpleDateFormat::translatePattern(const UnicodeString& originalPattern,
   3747                                         UnicodeString& translatedPattern,
   3748                                         const UnicodeString& from,
   3749                                         const UnicodeString& to,
   3750                                         UErrorCode& status)
   3751 {
   3752     // run through the pattern and convert any pattern symbols from the version
   3753     // in "from" to the corresponding character in "to".  This code takes
   3754     // quoted strings into account (it doesn't try to translate them), and it signals
   3755     // an error if a particular "pattern character" doesn't appear in "from".
   3756     // Depending on the values of "from" and "to" this can convert from generic
   3757     // to localized patterns or localized to generic.
   3758     if (U_FAILURE(status)) {
   3759         return;
   3760     }
   3761 
   3762     translatedPattern.remove();
   3763     UBool inQuote = FALSE;
   3764     for (int32_t i = 0; i < originalPattern.length(); ++i) {
   3765         UChar c = originalPattern[i];
   3766         if (inQuote) {
   3767             if (c == QUOTE) {
   3768                 inQuote = FALSE;
   3769             }
   3770         } else {
   3771             if (c == QUOTE) {
   3772                 inQuote = TRUE;
   3773             } else if (isSyntaxChar(c)) {
   3774                 int32_t ci = from.indexOf(c);
   3775                 if (ci == -1) {
   3776                     status = U_INVALID_FORMAT_ERROR;
   3777                     return;
   3778                 }
   3779                 c = to[ci];
   3780             }
   3781         }
   3782         translatedPattern += c;
   3783     }
   3784     if (inQuote) {
   3785         status = U_INVALID_FORMAT_ERROR;
   3786         return;
   3787     }
   3788 }
   3789 
   3790 //----------------------------------------------------------------------
   3791 
   3792 UnicodeString&
   3793 SimpleDateFormat::toPattern(UnicodeString& result) const
   3794 {
   3795     result = fPattern;
   3796     return result;
   3797 }
   3798 
   3799 //----------------------------------------------------------------------
   3800 
   3801 UnicodeString&
   3802 SimpleDateFormat::toLocalizedPattern(UnicodeString& result,
   3803                                      UErrorCode& status) const
   3804 {
   3805     translatePattern(fPattern, result,
   3806                      UnicodeString(DateFormatSymbols::getPatternUChars()),
   3807                      fSymbols->fLocalPatternChars, status);
   3808     return result;
   3809 }
   3810 
   3811 //----------------------------------------------------------------------
   3812 
   3813 void
   3814 SimpleDateFormat::applyPattern(const UnicodeString& pattern)
   3815 {
   3816     fPattern = pattern;
   3817     parsePattern();
   3818 }
   3819 
   3820 //----------------------------------------------------------------------
   3821 
   3822 void
   3823 SimpleDateFormat::applyLocalizedPattern(const UnicodeString& pattern,
   3824                                         UErrorCode &status)
   3825 {
   3826     translatePattern(pattern, fPattern,
   3827                      fSymbols->fLocalPatternChars,
   3828                      UnicodeString(DateFormatSymbols::getPatternUChars()), status);
   3829 }
   3830 
   3831 //----------------------------------------------------------------------
   3832 
   3833 const DateFormatSymbols*
   3834 SimpleDateFormat::getDateFormatSymbols() const
   3835 {
   3836     return fSymbols;
   3837 }
   3838 
   3839 //----------------------------------------------------------------------
   3840 
   3841 void
   3842 SimpleDateFormat::adoptDateFormatSymbols(DateFormatSymbols* newFormatSymbols)
   3843 {
   3844     delete fSymbols;
   3845     fSymbols = newFormatSymbols;
   3846 }
   3847 
   3848 //----------------------------------------------------------------------
   3849 void
   3850 SimpleDateFormat::setDateFormatSymbols(const DateFormatSymbols& newFormatSymbols)
   3851 {
   3852     delete fSymbols;
   3853     fSymbols = new DateFormatSymbols(newFormatSymbols);
   3854 }
   3855 
   3856 //----------------------------------------------------------------------
   3857 const TimeZoneFormat*
   3858 SimpleDateFormat::getTimeZoneFormat(void) const {
   3859     return (const TimeZoneFormat*)tzFormat();
   3860 }
   3861 
   3862 //----------------------------------------------------------------------
   3863 void
   3864 SimpleDateFormat::adoptTimeZoneFormat(TimeZoneFormat* timeZoneFormatToAdopt)
   3865 {
   3866     delete fTimeZoneFormat;
   3867     fTimeZoneFormat = timeZoneFormatToAdopt;
   3868 }
   3869 
   3870 //----------------------------------------------------------------------
   3871 void
   3872 SimpleDateFormat::setTimeZoneFormat(const TimeZoneFormat& newTimeZoneFormat)
   3873 {
   3874     delete fTimeZoneFormat;
   3875     fTimeZoneFormat = new TimeZoneFormat(newTimeZoneFormat);
   3876 }
   3877 
   3878 //----------------------------------------------------------------------
   3879 
   3880 
   3881 void SimpleDateFormat::adoptCalendar(Calendar* calendarToAdopt)
   3882 {
   3883   UErrorCode status = U_ZERO_ERROR;
   3884   Locale calLocale(fLocale);
   3885   calLocale.setKeywordValue("calendar", calendarToAdopt->getType(), status);
   3886   DateFormatSymbols *newSymbols =
   3887           DateFormatSymbols::createForLocale(calLocale, status);
   3888   if (U_FAILURE(status)) {
   3889       return;
   3890   }
   3891   DateFormat::adoptCalendar(calendarToAdopt);
   3892   delete fSymbols;
   3893   fSymbols = newSymbols;
   3894   initializeDefaultCentury();  // we need a new century (possibly)
   3895 }
   3896 
   3897 
   3898 //----------------------------------------------------------------------
   3899 
   3900 
   3901 // override the DateFormat implementation in order to
   3902 // lazily initialize fCapitalizationBrkIter
   3903 void
   3904 SimpleDateFormat::setContext(UDisplayContext value, UErrorCode& status)
   3905 {
   3906     DateFormat::setContext(value, status);
   3907 #if !UCONFIG_NO_BREAK_ITERATION
   3908     if (U_SUCCESS(status)) {
   3909         if ( fCapitalizationBrkIter == NULL && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
   3910                 value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE) ) {
   3911             UErrorCode status = U_ZERO_ERROR;
   3912             fCapitalizationBrkIter = BreakIterator::createSentenceInstance(fLocale, status);
   3913             if (U_FAILURE(status)) {
   3914                 delete fCapitalizationBrkIter;
   3915                 fCapitalizationBrkIter = NULL;
   3916             }
   3917         }
   3918     }
   3919 #endif
   3920 }
   3921 
   3922 
   3923 //----------------------------------------------------------------------
   3924 
   3925 
   3926 UBool
   3927 SimpleDateFormat::isFieldUnitIgnored(UCalendarDateFields field) const {
   3928     return isFieldUnitIgnored(fPattern, field);
   3929 }
   3930 
   3931 
   3932 UBool
   3933 SimpleDateFormat::isFieldUnitIgnored(const UnicodeString& pattern,
   3934                                      UCalendarDateFields field) {
   3935     int32_t fieldLevel = fgCalendarFieldToLevel[field];
   3936     int32_t level;
   3937     UChar ch;
   3938     UBool inQuote = FALSE;
   3939     UChar prevCh = 0;
   3940     int32_t count = 0;
   3941 
   3942     for (int32_t i = 0; i < pattern.length(); ++i) {
   3943         ch = pattern[i];
   3944         if (ch != prevCh && count > 0) {
   3945             level = getLevelFromChar(prevCh);
   3946             // the larger the level, the smaller the field unit.
   3947             if (fieldLevel <= level) {
   3948                 return FALSE;
   3949             }
   3950             count = 0;
   3951         }
   3952         if (ch == QUOTE) {
   3953             if ((i+1) < pattern.length() && pattern[i+1] == QUOTE) {
   3954                 ++i;
   3955             } else {
   3956                 inQuote = ! inQuote;
   3957             }
   3958         }
   3959         else if (!inQuote && isSyntaxChar(ch)) {
   3960             prevCh = ch;
   3961             ++count;
   3962         }
   3963     }
   3964     if (count > 0) {
   3965         // last item
   3966         level = getLevelFromChar(prevCh);
   3967         if (fieldLevel <= level) {
   3968             return FALSE;
   3969         }
   3970     }
   3971     return TRUE;
   3972 }
   3973 
   3974 //----------------------------------------------------------------------
   3975 
   3976 const Locale&
   3977 SimpleDateFormat::getSmpFmtLocale(void) const {
   3978     return fLocale;
   3979 }
   3980 
   3981 //----------------------------------------------------------------------
   3982 
   3983 int32_t
   3984 SimpleDateFormat::checkIntSuffix(const UnicodeString& text, int32_t start,
   3985                                  int32_t patLoc, UBool isNegative) const {
   3986     // local variables
   3987     UnicodeString suf;
   3988     int32_t patternMatch;
   3989     int32_t textPreMatch;
   3990     int32_t textPostMatch;
   3991 
   3992     // check that we are still in range
   3993     if ( (start > text.length()) ||
   3994          (start < 0) ||
   3995          (patLoc < 0) ||
   3996          (patLoc > fPattern.length())) {
   3997         // out of range, don't advance location in text
   3998         return start;
   3999     }
   4000 
   4001     // get the suffix
   4002     DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(fNumberFormat);
   4003     if (decfmt != NULL) {
   4004         if (isNegative) {
   4005             suf = decfmt->getNegativeSuffix(suf);
   4006         }
   4007         else {
   4008             suf = decfmt->getPositiveSuffix(suf);
   4009         }
   4010     }
   4011 
   4012     // check for suffix
   4013     if (suf.length() <= 0) {
   4014         return start;
   4015     }
   4016 
   4017     // check suffix will be encountered in the pattern
   4018     patternMatch = compareSimpleAffix(suf,fPattern,patLoc);
   4019 
   4020     // check if a suffix will be encountered in the text
   4021     textPreMatch = compareSimpleAffix(suf,text,start);
   4022 
   4023     // check if a suffix was encountered in the text
   4024     textPostMatch = compareSimpleAffix(suf,text,start-suf.length());
   4025 
   4026     // check for suffix match
   4027     if ((textPreMatch >= 0) && (patternMatch >= 0) && (textPreMatch == patternMatch)) {
   4028         return start;
   4029     }
   4030     else if ((textPostMatch >= 0) && (patternMatch >= 0) && (textPostMatch == patternMatch)) {
   4031         return  start - suf.length();
   4032     }
   4033 
   4034     // should not get here
   4035     return start;
   4036 }
   4037 
   4038 //----------------------------------------------------------------------
   4039 
   4040 int32_t
   4041 SimpleDateFormat::compareSimpleAffix(const UnicodeString& affix,
   4042                    const UnicodeString& input,
   4043                    int32_t pos) const {
   4044     int32_t start = pos;
   4045     for (int32_t i=0; i<affix.length(); ) {
   4046         UChar32 c = affix.char32At(i);
   4047         int32_t len = U16_LENGTH(c);
   4048         if (PatternProps::isWhiteSpace(c)) {
   4049             // We may have a pattern like: \u200F \u0020
   4050             //        and input text like: \u200F \u0020
   4051             // Note that U+200F and U+0020 are Pattern_White_Space but only
   4052             // U+0020 is UWhiteSpace.  So we have to first do a direct
   4053             // match of the run of Pattern_White_Space in the pattern,
   4054             // then match any extra characters.
   4055             UBool literalMatch = FALSE;
   4056             while (pos < input.length() &&
   4057                    input.char32At(pos) == c) {
   4058                 literalMatch = TRUE;
   4059                 i += len;
   4060                 pos += len;
   4061                 if (i == affix.length()) {
   4062                     break;
   4063                 }
   4064                 c = affix.char32At(i);
   4065                 len = U16_LENGTH(c);
   4066                 if (!PatternProps::isWhiteSpace(c)) {
   4067                     break;
   4068                 }
   4069             }
   4070 
   4071             // Advance over run in pattern
   4072             i = skipPatternWhiteSpace(affix, i);
   4073 
   4074             // Advance over run in input text
   4075             // Must see at least one white space char in input,
   4076             // unless we've already matched some characters literally.
   4077             int32_t s = pos;
   4078             pos = skipUWhiteSpace(input, pos);
   4079             if (pos == s && !literalMatch) {
   4080                 return -1;
   4081             }
   4082 
   4083             // If we skip UWhiteSpace in the input text, we need to skip it in the pattern.
   4084             // Otherwise, the previous lines may have skipped over text (such as U+00A0) that
   4085             // is also in the affix.
   4086             i = skipUWhiteSpace(affix, i);
   4087         } else {
   4088             if (pos < input.length() &&
   4089                 input.char32At(pos) == c) {
   4090                 i += len;
   4091                 pos += len;
   4092             } else {
   4093                 return -1;
   4094             }
   4095         }
   4096     }
   4097     return pos - start;
   4098 }
   4099 
   4100 //----------------------------------------------------------------------
   4101 
   4102 int32_t
   4103 SimpleDateFormat::skipPatternWhiteSpace(const UnicodeString& text, int32_t pos) const {
   4104     const UChar* s = text.getBuffer();
   4105     return (int32_t)(PatternProps::skipWhiteSpace(s + pos, text.length() - pos) - s);
   4106 }
   4107 
   4108 //----------------------------------------------------------------------
   4109 
   4110 int32_t
   4111 SimpleDateFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) const {
   4112     while (pos < text.length()) {
   4113         UChar32 c = text.char32At(pos);
   4114         if (!u_isUWhiteSpace(c)) {
   4115             break;
   4116         }
   4117         pos += U16_LENGTH(c);
   4118     }
   4119     return pos;
   4120 }
   4121 
   4122 //----------------------------------------------------------------------
   4123 
   4124 // Lazy TimeZoneFormat instantiation, semantically const.
   4125 TimeZoneFormat *
   4126 SimpleDateFormat::tzFormat() const {
   4127     if (fTimeZoneFormat == NULL) {
   4128         umtx_lock(&LOCK);
   4129         {
   4130             if (fTimeZoneFormat == NULL) {
   4131                 UErrorCode status = U_ZERO_ERROR;
   4132                 TimeZoneFormat *tzfmt = TimeZoneFormat::createInstance(fLocale, status);
   4133                 if (U_FAILURE(status)) {
   4134                     return NULL;
   4135                 }
   4136 
   4137                 const_cast<SimpleDateFormat *>(this)->fTimeZoneFormat = tzfmt;
   4138             }
   4139         }
   4140         umtx_unlock(&LOCK);
   4141     }
   4142     return fTimeZoneFormat;
   4143 }
   4144 
   4145 void SimpleDateFormat::parsePattern() {
   4146     fHasMinute = FALSE;
   4147     fHasSecond = FALSE;
   4148 
   4149     int len = fPattern.length();
   4150     UBool inQuote = FALSE;
   4151     for (int32_t i = 0; i < len; ++i) {
   4152         UChar ch = fPattern[i];
   4153         if (ch == QUOTE) {
   4154             inQuote = !inQuote;
   4155         }
   4156         if (!inQuote) {
   4157             if (ch == 0x6D) {  // 0x6D == 'm'
   4158                 fHasMinute = TRUE;
   4159             }
   4160             if (ch == 0x73) {  // 0x73 == 's'
   4161                 fHasSecond = TRUE;
   4162             }
   4163         }
   4164     }
   4165 }
   4166 
   4167 U_NAMESPACE_END
   4168 
   4169 #endif /* #if !UCONFIG_NO_FORMATTING */
   4170 
   4171 //eof
   4172