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