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