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