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