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