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