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