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
68U_NAMESPACE_BEGIN
69
70static 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.
78static const UChar gGmt[]      = {0x0047, 0x004D, 0x0054, 0x0000};         // "GMT"
79static const UChar gGmtPlus[]  = {0x0047, 0x004D, 0x0054, 0x002B, 0x0000}; // "GMT+"
80static const UChar gGmtMinus[] = {0x0047, 0x004D, 0x0054, 0x002D, 0x0000}; // "GMT-"
81static const UChar gDefGmtPat[]       = {0x0047, 0x004D, 0x0054, 0x007B, 0x0030, 0x007D, 0x0000}; /* GMT{0} */
82static const UChar gDefGmtNegHmsPat[] = {0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0x0000}; /* -HH:mm:ss */
83static const UChar gDefGmtNegHmPat[]  = {0x002D, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x0000}; /* -HH:mm */
84static const UChar gDefGmtPosHmsPat[] = {0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x003A, 0x0073, 0x0073, 0x0000}; /* +HH:mm:ss */
85static const UChar gDefGmtPosHmPat[]  = {0x002B, 0x0048, 0x0048, 0x003A, 0x006D, 0x006D, 0x0000}; /* +HH:mm */
86static const UChar gUt[]       = {0x0055, 0x0054, 0x0000};  // "UT"
87static const UChar gUtc[]      = {0x0055, 0x0054, 0x0043, 0x0000};  // "UT"
88
89typedef 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
102typedef enum OvrStrType {
103    kOvrStrDate = 0,
104    kOvrStrTime = 1,
105    kOvrStrBoth = 2
106} OvrStrType;
107
108static 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 };
123static const int8_t kDateFieldsCount = 13;
124
125static 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 };
135static 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.
140static 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).
148static 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 */
154static const char gDateTimePatternsTag[]="DateTimePatterns";
155
156static const UChar gEtcUTC[] = {0x45, 0x74, 0x63, 0x2F, 0x55, 0x54, 0x43, 0x00}; // "Etc/UTC"
157static const UChar QUOTE = 0x27; // Single quote
158
159static UMTX LOCK;
160
161UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SimpleDateFormat)
162
163//----------------------------------------------------------------------
164
165SimpleDateFormat::~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
191SimpleDateFormat::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
204SimpleDateFormat::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
222SimpleDateFormat::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
244SimpleDateFormat::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
264SimpleDateFormat::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
288SimpleDateFormat::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
309SimpleDateFormat::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
331SimpleDateFormat::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 */
354SimpleDateFormat::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
389SimpleDateFormat::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
401SimpleDateFormat& 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
425Format*
426SimpleDateFormat::clone() const
427{
428    return new SimpleDateFormat(*this);
429}
430
431//----------------------------------------------------------------------
432
433UBool
434SimpleDateFormat::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
451void 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
644Calendar*
645SimpleDateFormat::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
656void
657SimpleDateFormat::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
672void
673SimpleDateFormat::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 */
705void 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 */
722void 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
742UnicodeString&
743SimpleDateFormat::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
752UnicodeString&
753SimpleDateFormat::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
762UnicodeString&
763SimpleDateFormat::_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 */
837const int32_t
838SimpleDateFormat::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 */
855const int32_t
856SimpleDateFormat::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.
869const UCalendarDateFields
870SimpleDateFormat::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
889const UDateFormatField
890SimpleDateFormat::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 */
913static 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//---------------------------------------------------------------------
925void
926SimpleDateFormat::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
950int32_t
951SimpleDateFormat::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
1029void
1030SimpleDateFormat::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
1054int32_t
1055SimpleDateFormat::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
1167UBool
1168SimpleDateFormat::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
1189void
1190SimpleDateFormat::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
1222void
1223SimpleDateFormat::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
1282void
1283SimpleDateFormat::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
1308void
1309SimpleDateFormat::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//---------------------------------------------------------------------
1431void
1432SimpleDateFormat::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
1732NumberFormat *
1733SimpleDateFormat::getNumberFormat(UDateFormatField index) const {
1734    if (fNumberFormatters != NULL) {
1735        return fNumberFormatters[index];
1736    } else {
1737        return fNumberFormat;
1738    }
1739}
1740
1741//----------------------------------------------------------------------
1742void
1743SimpleDateFormat::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 */
1761static 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 */
1767UBool 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
1773void
1774SimpleDateFormat::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    }
2127ExitParse:
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
2149UDate
2150SimpleDateFormat::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
2157UDate
2158SimpleDateFormat::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
2166int32_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
2244int32_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
2330void
2331SimpleDateFormat::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 */
2346int32_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 */
2885void 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 */
2896void 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
2935void 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
2981UnicodeString&
2982SimpleDateFormat::toPattern(UnicodeString& result) const
2983{
2984    result = fPattern;
2985    return result;
2986}
2987
2988//----------------------------------------------------------------------
2989
2990UnicodeString&
2991SimpleDateFormat::toLocalizedPattern(UnicodeString& result,
2992                                     UErrorCode& status) const
2993{
2994    translatePattern(fPattern, result, DateFormatSymbols::getPatternUChars(), fSymbols->fLocalPatternChars, status);
2995    return result;
2996}
2997
2998//----------------------------------------------------------------------
2999
3000void
3001SimpleDateFormat::applyPattern(const UnicodeString& pattern)
3002{
3003    fPattern = pattern;
3004}
3005
3006//----------------------------------------------------------------------
3007
3008void
3009SimpleDateFormat::applyLocalizedPattern(const UnicodeString& pattern,
3010                                        UErrorCode &status)
3011{
3012    translatePattern(pattern, fPattern, fSymbols->fLocalPatternChars, DateFormatSymbols::getPatternUChars(), status);
3013}
3014
3015//----------------------------------------------------------------------
3016
3017const DateFormatSymbols*
3018SimpleDateFormat::getDateFormatSymbols() const
3019{
3020    return fSymbols;
3021}
3022
3023//----------------------------------------------------------------------
3024
3025void
3026SimpleDateFormat::adoptDateFormatSymbols(DateFormatSymbols* newFormatSymbols)
3027{
3028    delete fSymbols;
3029    fSymbols = newFormatSymbols;
3030}
3031
3032//----------------------------------------------------------------------
3033void
3034SimpleDateFormat::setDateFormatSymbols(const DateFormatSymbols& newFormatSymbols)
3035{
3036    delete fSymbols;
3037    fSymbols = new DateFormatSymbols(newFormatSymbols);
3038}
3039
3040
3041//----------------------------------------------------------------------
3042
3043
3044void 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
3058UBool
3059SimpleDateFormat::isFieldUnitIgnored(UCalendarDateFields field) const {
3060    return isFieldUnitIgnored(fPattern, field);
3061}
3062
3063
3064UBool
3065SimpleDateFormat::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
3109const Locale&
3110SimpleDateFormat::getSmpFmtLocale(void) const {
3111    return fLocale;
3112}
3113
3114//----------------------------------------------------------------------
3115
3116int32_t
3117SimpleDateFormat::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
3172int32_t
3173SimpleDateFormat::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
3234int32_t
3235SimpleDateFormat::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
3248int32_t
3249SimpleDateFormat::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
3260U_NAMESPACE_END
3261
3262#endif /* #if !UCONFIG_NO_FORMATTING */
3263
3264//eof
3265