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