• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = U_MUTEX_INITIALIZER;
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 Format*
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     // We don't need to check that the row count is >= 1, since all 2d arrays have at
860     // least one row
861     fNumberFormat = NumberFormat::createInstance(locale, status);
862     if (fNumberFormat != NULL && U_SUCCESS(status))
863     {
864         fixNumberFormatForDates(*fNumberFormat);
865         //fNumberFormat->setLenient(TRUE); // Java uses a custom DateNumberFormat to format/parse
866 
867         initNumberFormatters(locale, status);
868         initFastNumberFormatters(status);
869 
870     }
871     else if (U_SUCCESS(status))
872     {
873         status = U_MISSING_RESOURCE_ERROR;
874     }
875 
876     parsePattern();
877 }
878 
879 /* Initialize the fields we use to disambiguate ambiguous years. Separate
880  * so we can call it from readObject().
881  */
initializeDefaultCentury()882 void SimpleDateFormat::initializeDefaultCentury()
883 {
884   if(fCalendar) {
885     fHaveDefaultCentury = fCalendar->haveDefaultCentury();
886     if(fHaveDefaultCentury) {
887       fDefaultCenturyStart = fCalendar->defaultCenturyStart();
888       fDefaultCenturyStartYear = fCalendar->defaultCenturyStartYear();
889     } else {
890       fDefaultCenturyStart = DBL_MIN;
891       fDefaultCenturyStartYear = -1;
892     }
893   }
894 }
895 
896 /*
897  * Initialize the boolean attributes. Separate so we can call it from all constructors.
898  */
initializeBooleanAttributes()899 void SimpleDateFormat::initializeBooleanAttributes()
900 {
901     UErrorCode status = U_ZERO_ERROR;
902 
903     setBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, true, status);
904     setBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, true, status);
905     setBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, true, status);
906     setBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, true, status);
907 }
908 
909 /* Define one-century window into which to disambiguate dates using
910  * two-digit years. Make public in JDK 1.2.
911  */
parseAmbiguousDatesAsAfter(UDate startDate,UErrorCode & status)912 void SimpleDateFormat::parseAmbiguousDatesAsAfter(UDate startDate, UErrorCode& status)
913 {
914     if(U_FAILURE(status)) {
915         return;
916     }
917     if(!fCalendar) {
918       status = U_ILLEGAL_ARGUMENT_ERROR;
919       return;
920     }
921 
922     fCalendar->setTime(startDate, status);
923     if(U_SUCCESS(status)) {
924         fHaveDefaultCentury = TRUE;
925         fDefaultCenturyStart = startDate;
926         fDefaultCenturyStartYear = fCalendar->get(UCAL_YEAR, status);
927     }
928 }
929 
930 //----------------------------------------------------------------------
931 
932 UnicodeString&
format(Calendar & cal,UnicodeString & appendTo,FieldPosition & pos) const933 SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo, FieldPosition& pos) const
934 {
935   UErrorCode status = U_ZERO_ERROR;
936   FieldPositionOnlyHandler handler(pos);
937   return _format(cal, appendTo, handler, status);
938 }
939 
940 //----------------------------------------------------------------------
941 
942 UnicodeString&
format(Calendar & cal,UnicodeString & appendTo,FieldPositionIterator * posIter,UErrorCode & status) const943 SimpleDateFormat::format(Calendar& cal, UnicodeString& appendTo,
944                          FieldPositionIterator* posIter, UErrorCode& status) const
945 {
946   FieldPositionIteratorHandler handler(posIter, status);
947   return _format(cal, appendTo, handler, status);
948 }
949 
950 //----------------------------------------------------------------------
951 
952 UnicodeString&
_format(Calendar & cal,UnicodeString & appendTo,FieldPositionHandler & handler,UErrorCode & status) const953 SimpleDateFormat::_format(Calendar& cal, UnicodeString& appendTo,
954                             FieldPositionHandler& handler, UErrorCode& status) const
955 {
956     if ( U_FAILURE(status) ) {
957        return appendTo;
958     }
959     Calendar* workCal = &cal;
960     Calendar* calClone = NULL;
961     if (&cal != fCalendar && uprv_strcmp(cal.getType(), fCalendar->getType()) != 0) {
962         // Different calendar type
963         // We use the time and time zone from the input calendar, but
964         // do not use the input calendar for field calculation.
965         calClone = fCalendar->clone();
966         if (calClone != NULL) {
967             UDate t = cal.getTime(status);
968             calClone->setTime(t, status);
969             calClone->setTimeZone(cal.getTimeZone());
970             workCal = calClone;
971         } else {
972             status = U_MEMORY_ALLOCATION_ERROR;
973             return appendTo;
974         }
975     }
976 
977     UBool inQuote = FALSE;
978     UChar prevCh = 0;
979     int32_t count = 0;
980     int32_t fieldNum = 0;
981     UDisplayContext capitalizationContext = getContext(UDISPCTX_TYPE_CAPITALIZATION, status);
982 
983     // loop through the pattern string character by character
984     for (int32_t i = 0; i < fPattern.length() && U_SUCCESS(status); ++i) {
985         UChar ch = fPattern[i];
986 
987         // Use subFormat() to format a repeated pattern character
988         // when a different pattern or non-pattern character is seen
989         if (ch != prevCh && count > 0) {
990             subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++, handler, *workCal, status);
991             count = 0;
992         }
993         if (ch == QUOTE) {
994             // Consecutive single quotes are a single quote literal,
995             // either outside of quotes or between quotes
996             if ((i+1) < fPattern.length() && fPattern[i+1] == QUOTE) {
997                 appendTo += (UChar)QUOTE;
998                 ++i;
999             } else {
1000                 inQuote = ! inQuote;
1001             }
1002         }
1003         else if (!inQuote && isSyntaxChar(ch)) {
1004             // ch is a date-time pattern character to be interpreted
1005             // by subFormat(); count the number of times it is repeated
1006             prevCh = ch;
1007             ++count;
1008         }
1009         else {
1010             // Append quoted characters and unquoted non-pattern characters
1011             appendTo += ch;
1012         }
1013     }
1014 
1015     // Format the last item in the pattern, if any
1016     if (count > 0) {
1017         subFormat(appendTo, prevCh, count, capitalizationContext, fieldNum++, handler, *workCal, status);
1018     }
1019 
1020     if (calClone != NULL) {
1021         delete calClone;
1022     }
1023 
1024     return appendTo;
1025 }
1026 
1027 //----------------------------------------------------------------------
1028 
1029 /* Map calendar field into calendar field level.
1030  * the larger the level, the smaller the field unit.
1031  * For example, UCAL_ERA level is 0, UCAL_YEAR level is 10,
1032  * UCAL_MONTH level is 20.
1033  * NOTE: if new fields adds in, the table needs to update.
1034  */
1035 const int32_t
1036 SimpleDateFormat::fgCalendarFieldToLevel[] =
1037 {
1038     /*GyM*/ 0, 10, 20,
1039     /*wW*/ 20, 30,
1040     /*dDEF*/ 30, 20, 30, 30,
1041     /*ahHm*/ 40, 50, 50, 60,
1042     /*sS*/ 70, 80,
1043     /*z?Y*/ 0, 0, 10,
1044     /*eug*/ 30, 10, 0,
1045     /*A?.*/ 40, 0, 0
1046 };
1047 
getLevelFromChar(UChar ch)1048 int32_t SimpleDateFormat::getLevelFromChar(UChar ch) {
1049     // Map date field LETTER into calendar field level.
1050     // the larger the level, the smaller the field unit.
1051     // NOTE: if new fields adds in, the table needs to update.
1052     static const int32_t mapCharToLevel[] = {
1053             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1054         //
1055             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1056         //       !   "   #   $   %   &   '   (   )   *   +   ,   -   .   /
1057             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1058 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
1059         //   0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?
1060             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,  0, -1, -1, -1, -1, -1,
1061 #else
1062         //   0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?
1063             -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
1064 #endif
1065         //   @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
1066             -1, 40, -1, -1, 20, 30, 30,  0, 50, -1, -1, 50, 20, 20, -1,  0,
1067         //   P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _
1068             -1, 20, -1, 80, -1, 10,  0, 30,  0, 10,  0, -1, -1, -1, -1, -1,
1069         //   `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
1070             -1, 40, -1, 30, 30, 30, -1,  0, 50, -1, -1, 50,  0, 60, -1, -1,
1071         //   p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~
1072             -1, 20, 10, 70, -1, 10,  0, 20,  0, 10,  0, -1, -1, -1, -1, -1
1073     };
1074 
1075     return ch < UPRV_LENGTHOF(mapCharToLevel) ? mapCharToLevel[ch] : -1;
1076 }
1077 
isSyntaxChar(UChar ch)1078 UBool SimpleDateFormat::isSyntaxChar(UChar ch) {
1079     static const UBool mapCharToIsSyntax[] = {
1080         //
1081         FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
1082         //
1083         FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
1084         //
1085         FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
1086         //
1087         FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
1088         //         !      "      #      $      %      &      '
1089         FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
1090         //  (      )      *      +      ,      -      .      /
1091         FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
1092         //  0      1      2      3      4      5      6      7
1093         FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
1094 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
1095         //  8      9      :      ;      <      =      >      ?
1096         FALSE, FALSE,  TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,
1097 #else
1098         //  8      9      :      ;      <      =      >      ?
1099         FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
1100 #endif
1101         //  @      A      B      C      D      E      F      G
1102         FALSE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,
1103         //  H      I      J      K      L      M      N      O
1104          TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,
1105         //  P      Q      R      S      T      U      V      W
1106          TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,
1107         //  X      Y      Z      [      \      ]      ^      _
1108          TRUE,  TRUE,  TRUE, FALSE, FALSE, FALSE, FALSE, FALSE,
1109         //  `      a      b      c      d      e      f      g
1110         FALSE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,
1111         //  h      i      j      k      l      m      n      o
1112          TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,
1113         //  p      q      r      s      t      u      v      w
1114          TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,  TRUE,
1115         //  x      y      z      {      |      }      ~
1116          TRUE,  TRUE,  TRUE, FALSE, FALSE, FALSE, FALSE, FALSE
1117     };
1118 
1119     return ch < UPRV_LENGTHOF(mapCharToIsSyntax) ? mapCharToIsSyntax[ch] : FALSE;
1120 }
1121 
1122 // Map index into pattern character string to Calendar field number.
1123 const UCalendarDateFields
1124 SimpleDateFormat::fgPatternIndexToCalendarField[] =
1125 {
1126     /*GyM*/ UCAL_ERA, UCAL_YEAR, UCAL_MONTH,
1127     /*dkH*/ UCAL_DATE, UCAL_HOUR_OF_DAY, UCAL_HOUR_OF_DAY,
1128     /*msS*/ UCAL_MINUTE, UCAL_SECOND, UCAL_MILLISECOND,
1129     /*EDF*/ UCAL_DAY_OF_WEEK, UCAL_DAY_OF_YEAR, UCAL_DAY_OF_WEEK_IN_MONTH,
1130     /*wWa*/ UCAL_WEEK_OF_YEAR, UCAL_WEEK_OF_MONTH, UCAL_AM_PM,
1131     /*hKz*/ UCAL_HOUR, UCAL_HOUR, UCAL_ZONE_OFFSET,
1132     /*Yeu*/ UCAL_YEAR_WOY, UCAL_DOW_LOCAL, UCAL_EXTENDED_YEAR,
1133     /*gAZ*/ UCAL_JULIAN_DAY, UCAL_MILLISECONDS_IN_DAY, UCAL_ZONE_OFFSET,
1134     /*v*/   UCAL_ZONE_OFFSET,
1135     /*c*/   UCAL_DOW_LOCAL,
1136     /*L*/   UCAL_MONTH,
1137     /*Q*/   UCAL_MONTH,
1138     /*q*/   UCAL_MONTH,
1139     /*V*/   UCAL_ZONE_OFFSET,
1140     /*U*/   UCAL_YEAR,
1141     /*O*/   UCAL_ZONE_OFFSET,
1142     /*Xx*/  UCAL_ZONE_OFFSET, UCAL_ZONE_OFFSET,
1143     /*r*/   UCAL_EXTENDED_YEAR,
1144     /*bB*/   UCAL_FIELD_COUNT, UCAL_FIELD_COUNT,  // no mappings to calendar fields
1145 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
1146     /*:*/   UCAL_FIELD_COUNT, /* => no useful mapping to any calendar field */
1147 #else
1148     /*no pattern char for UDAT_TIME_SEPARATOR_FIELD*/   UCAL_FIELD_COUNT, /* => no useful mapping to any calendar field */
1149 #endif
1150 };
1151 
1152 // Map index into pattern character string to DateFormat field number
1153 const UDateFormatField
1154 SimpleDateFormat::fgPatternIndexToDateFormatField[] = {
1155     /*GyM*/ UDAT_ERA_FIELD, UDAT_YEAR_FIELD, UDAT_MONTH_FIELD,
1156     /*dkH*/ UDAT_DATE_FIELD, UDAT_HOUR_OF_DAY1_FIELD, UDAT_HOUR_OF_DAY0_FIELD,
1157     /*msS*/ UDAT_MINUTE_FIELD, UDAT_SECOND_FIELD, UDAT_FRACTIONAL_SECOND_FIELD,
1158     /*EDF*/ UDAT_DAY_OF_WEEK_FIELD, UDAT_DAY_OF_YEAR_FIELD, UDAT_DAY_OF_WEEK_IN_MONTH_FIELD,
1159     /*wWa*/ UDAT_WEEK_OF_YEAR_FIELD, UDAT_WEEK_OF_MONTH_FIELD, UDAT_AM_PM_FIELD,
1160     /*hKz*/ UDAT_HOUR1_FIELD, UDAT_HOUR0_FIELD, UDAT_TIMEZONE_FIELD,
1161     /*Yeu*/ UDAT_YEAR_WOY_FIELD, UDAT_DOW_LOCAL_FIELD, UDAT_EXTENDED_YEAR_FIELD,
1162     /*gAZ*/ UDAT_JULIAN_DAY_FIELD, UDAT_MILLISECONDS_IN_DAY_FIELD, UDAT_TIMEZONE_RFC_FIELD,
1163     /*v*/   UDAT_TIMEZONE_GENERIC_FIELD,
1164     /*c*/   UDAT_STANDALONE_DAY_FIELD,
1165     /*L*/   UDAT_STANDALONE_MONTH_FIELD,
1166     /*Q*/   UDAT_QUARTER_FIELD,
1167     /*q*/   UDAT_STANDALONE_QUARTER_FIELD,
1168     /*V*/   UDAT_TIMEZONE_SPECIAL_FIELD,
1169     /*U*/   UDAT_YEAR_NAME_FIELD,
1170     /*O*/   UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD,
1171     /*Xx*/  UDAT_TIMEZONE_ISO_FIELD, UDAT_TIMEZONE_ISO_LOCAL_FIELD,
1172     /*r*/   UDAT_RELATED_YEAR_FIELD,
1173     /*bB*/  UDAT_AM_PM_MIDNIGHT_NOON_FIELD, UDAT_FLEXIBLE_DAY_PERIOD_FIELD,
1174 #if UDAT_HAS_PATTERN_CHAR_FOR_TIME_SEPARATOR
1175     /*:*/   UDAT_TIME_SEPARATOR_FIELD,
1176 #else
1177     /*no pattern char for UDAT_TIME_SEPARATOR_FIELD*/   UDAT_TIME_SEPARATOR_FIELD,
1178 #endif
1179 };
1180 
1181 //----------------------------------------------------------------------
1182 
1183 /**
1184  * Append symbols[value] to dst.  Make sure the array index is not out
1185  * of bounds.
1186  */
1187 static inline void
_appendSymbol(UnicodeString & dst,int32_t value,const UnicodeString * symbols,int32_t symbolsCount)1188 _appendSymbol(UnicodeString& dst,
1189               int32_t value,
1190               const UnicodeString* symbols,
1191               int32_t symbolsCount) {
1192     U_ASSERT(0 <= value && value < symbolsCount);
1193     if (0 <= value && value < symbolsCount) {
1194         dst += symbols[value];
1195     }
1196 }
1197 
1198 static inline void
_appendSymbolWithMonthPattern(UnicodeString & dst,int32_t value,const UnicodeString * symbols,int32_t symbolsCount,const UnicodeString * monthPattern,UErrorCode & status)1199 _appendSymbolWithMonthPattern(UnicodeString& dst, int32_t value, const UnicodeString* symbols, int32_t symbolsCount,
1200               const UnicodeString* monthPattern, UErrorCode& status) {
1201     U_ASSERT(0 <= value && value < symbolsCount);
1202     if (0 <= value && value < symbolsCount) {
1203         if (monthPattern == NULL) {
1204             dst += symbols[value];
1205         } else {
1206             SimpleFormatter(*monthPattern, 1, 1, status).format(symbols[value], dst, status);
1207         }
1208     }
1209 }
1210 
1211 //----------------------------------------------------------------------
1212 
1213 static number::LocalizedNumberFormatter*
createFastFormatter(const DecimalFormat * df,int32_t minInt,int32_t maxInt)1214 createFastFormatter(const DecimalFormat* df, int32_t minInt, int32_t maxInt) {
1215     return new number::LocalizedNumberFormatter(
1216             df->toNumberFormatter()
1217                     .integerWidth(number::IntegerWidth::zeroFillTo(minInt).truncateAt(maxInt)));
1218 }
1219 
initFastNumberFormatters(UErrorCode & status)1220 void SimpleDateFormat::initFastNumberFormatters(UErrorCode& status) {
1221     if (U_FAILURE(status)) {
1222         return;
1223     }
1224     auto* df = dynamic_cast<const DecimalFormat*>(fNumberFormat);
1225     if (df == nullptr) {
1226         return;
1227     }
1228     fFastNumberFormatters[SMPDTFMT_NF_1x10] = createFastFormatter(df, 1, 10);
1229     fFastNumberFormatters[SMPDTFMT_NF_2x10] = createFastFormatter(df, 2, 10);
1230     fFastNumberFormatters[SMPDTFMT_NF_3x10] = createFastFormatter(df, 3, 10);
1231     fFastNumberFormatters[SMPDTFMT_NF_4x10] = createFastFormatter(df, 4, 10);
1232     fFastNumberFormatters[SMPDTFMT_NF_2x2] = createFastFormatter(df, 2, 2);
1233 }
1234 
freeFastNumberFormatters()1235 void SimpleDateFormat::freeFastNumberFormatters() {
1236     delete fFastNumberFormatters[SMPDTFMT_NF_1x10];
1237     delete fFastNumberFormatters[SMPDTFMT_NF_2x10];
1238     delete fFastNumberFormatters[SMPDTFMT_NF_3x10];
1239     delete fFastNumberFormatters[SMPDTFMT_NF_4x10];
1240     delete fFastNumberFormatters[SMPDTFMT_NF_2x2];
1241     fFastNumberFormatters[SMPDTFMT_NF_1x10] = nullptr;
1242     fFastNumberFormatters[SMPDTFMT_NF_2x10] = nullptr;
1243     fFastNumberFormatters[SMPDTFMT_NF_3x10] = nullptr;
1244     fFastNumberFormatters[SMPDTFMT_NF_4x10] = nullptr;
1245     fFastNumberFormatters[SMPDTFMT_NF_2x2] = nullptr;
1246 }
1247 
1248 
1249 void
initNumberFormatters(const Locale & locale,UErrorCode & status)1250 SimpleDateFormat::initNumberFormatters(const Locale &locale,UErrorCode &status) {
1251     if (U_FAILURE(status)) {
1252         return;
1253     }
1254     if ( fDateOverride.isBogus() && fTimeOverride.isBogus() ) {
1255         return;
1256     }
1257     umtx_lock(&LOCK);
1258     if (fSharedNumberFormatters == NULL) {
1259         fSharedNumberFormatters = allocSharedNumberFormatters();
1260         if (fSharedNumberFormatters == NULL) {
1261             status = U_MEMORY_ALLOCATION_ERROR;
1262         }
1263     }
1264     umtx_unlock(&LOCK);
1265 
1266     if (U_FAILURE(status)) {
1267         return;
1268     }
1269 
1270     processOverrideString(locale,fDateOverride,kOvrStrDate,status);
1271     processOverrideString(locale,fTimeOverride,kOvrStrTime,status);
1272 }
1273 
1274 void
processOverrideString(const Locale & locale,const UnicodeString & str,int8_t type,UErrorCode & status)1275 SimpleDateFormat::processOverrideString(const Locale &locale, const UnicodeString &str, int8_t type, UErrorCode &status) {
1276     if (str.isBogus() || U_FAILURE(status)) {
1277         return;
1278     }
1279 
1280     int32_t start = 0;
1281     int32_t len;
1282     UnicodeString nsName;
1283     UnicodeString ovrField;
1284     UBool moreToProcess = TRUE;
1285     NSOverride *overrideList = NULL;
1286 
1287     while (moreToProcess) {
1288         int32_t delimiterPosition = str.indexOf((UChar)ULOC_KEYWORD_ITEM_SEPARATOR_UNICODE,start);
1289         if (delimiterPosition == -1) {
1290             moreToProcess = FALSE;
1291             len = str.length() - start;
1292         } else {
1293             len = delimiterPosition - start;
1294         }
1295         UnicodeString currentString(str,start,len);
1296         int32_t equalSignPosition = currentString.indexOf((UChar)ULOC_KEYWORD_ASSIGN_UNICODE,0);
1297         if (equalSignPosition == -1) { // Simple override string such as "hebrew"
1298             nsName.setTo(currentString);
1299             ovrField.setToBogus();
1300         } else { // Field specific override string such as "y=hebrew"
1301             nsName.setTo(currentString,equalSignPosition+1);
1302             ovrField.setTo(currentString,0,1); // We just need the first character.
1303         }
1304 
1305         int32_t nsNameHash = nsName.hashCode();
1306         // See if the numbering system is in the override list, if not, then add it.
1307         NSOverride *curr = overrideList;
1308         const SharedNumberFormat *snf = NULL;
1309         UBool found = FALSE;
1310         while ( curr && !found ) {
1311             if ( curr->hash == nsNameHash ) {
1312                 snf = curr->snf;
1313                 found = TRUE;
1314             }
1315             curr = curr->next;
1316         }
1317 
1318         if (!found) {
1319            LocalPointer<NSOverride> cur(new NSOverride);
1320            if (!cur.isNull()) {
1321                char kw[ULOC_KEYWORD_AND_VALUES_CAPACITY];
1322                uprv_strcpy(kw,"numbers=");
1323                nsName.extract(0,len,kw+8,ULOC_KEYWORD_AND_VALUES_CAPACITY-8,US_INV);
1324 
1325                Locale ovrLoc(locale.getLanguage(),locale.getCountry(),locale.getVariant(),kw);
1326                cur->hash = nsNameHash;
1327                cur->next = overrideList;
1328                SharedObject::copyPtr(
1329                        createSharedNumberFormat(ovrLoc, status), cur->snf);
1330                if (U_FAILURE(status)) {
1331                    if (overrideList) {
1332                        overrideList->free();
1333                    }
1334                    return;
1335                }
1336                snf = cur->snf;
1337                overrideList = cur.orphan();
1338            } else {
1339                status = U_MEMORY_ALLOCATION_ERROR;
1340                if (overrideList) {
1341                    overrideList->free();
1342                }
1343                return;
1344            }
1345         }
1346 
1347         // Now that we have an appropriate number formatter, fill in the appropriate spaces in the
1348         // number formatters table.
1349         if (ovrField.isBogus()) {
1350             switch (type) {
1351                 case kOvrStrDate:
1352                 case kOvrStrBoth: {
1353                     for ( int8_t i=0 ; i<kDateFieldsCount; i++ ) {
1354                         SharedObject::copyPtr(snf, fSharedNumberFormatters[kDateFields[i]]);
1355                     }
1356                     if (type==kOvrStrDate) {
1357                         break;
1358                     }
1359                     U_FALLTHROUGH;
1360                 }
1361                 case kOvrStrTime : {
1362                     for ( int8_t i=0 ; i<kTimeFieldsCount; i++ ) {
1363                         SharedObject::copyPtr(snf, fSharedNumberFormatters[kTimeFields[i]]);
1364                     }
1365                     break;
1366                 }
1367             }
1368         } else {
1369            // if the pattern character is unrecognized, signal an error and bail out
1370            UDateFormatField patternCharIndex =
1371               DateFormatSymbols::getPatternCharIndex(ovrField.charAt(0));
1372            if (patternCharIndex == UDAT_FIELD_COUNT) {
1373                status = U_INVALID_FORMAT_ERROR;
1374                if (overrideList) {
1375                    overrideList->free();
1376                }
1377                return;
1378            }
1379            SharedObject::copyPtr(snf, fSharedNumberFormatters[patternCharIndex]);
1380         }
1381 
1382         start = delimiterPosition + 1;
1383     }
1384     if (overrideList) {
1385         overrideList->free();
1386     }
1387 }
1388 
1389 //---------------------------------------------------------------------
1390 void
subFormat(UnicodeString & appendTo,UChar ch,int32_t count,UDisplayContext capitalizationContext,int32_t fieldNum,FieldPositionHandler & handler,Calendar & cal,UErrorCode & status) const1391 SimpleDateFormat::subFormat(UnicodeString &appendTo,
1392                             UChar ch,
1393                             int32_t count,
1394                             UDisplayContext capitalizationContext,
1395                             int32_t fieldNum,
1396                             FieldPositionHandler& handler,
1397                             Calendar& cal,
1398                             UErrorCode& status) const
1399 {
1400     if (U_FAILURE(status)) {
1401         return;
1402     }
1403 
1404     // this function gets called by format() to produce the appropriate substitution
1405     // text for an individual pattern symbol (e.g., "HH" or "yyyy")
1406 
1407     UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(ch);
1408     const int32_t maxIntCount = 10;
1409     int32_t beginOffset = appendTo.length();
1410     const NumberFormat *currentNumberFormat;
1411     DateFormatSymbols::ECapitalizationContextUsageType capContextUsageType = DateFormatSymbols::kCapContextUsageOther;
1412 
1413     UBool isHebrewCalendar = (uprv_strcmp(cal.getType(),"hebrew") == 0);
1414     UBool isChineseCalendar = (uprv_strcmp(cal.getType(),"chinese") == 0 || uprv_strcmp(cal.getType(),"dangi") == 0);
1415 
1416     // if the pattern character is unrecognized, signal an error and dump out
1417     if (patternCharIndex == UDAT_FIELD_COUNT)
1418     {
1419         if (ch != 0x6C) { // pattern char 'l' (SMALL LETTER L) just gets ignored
1420             status = U_INVALID_FORMAT_ERROR;
1421         }
1422         return;
1423     }
1424 
1425     UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex];
1426     int32_t value = 0;
1427     // Don't get value unless it is useful
1428     if (field < UCAL_FIELD_COUNT) {
1429         value = (patternCharIndex != UDAT_RELATED_YEAR_FIELD)? cal.get(field, status): cal.getRelatedYear(status);
1430     }
1431     if (U_FAILURE(status)) {
1432         return;
1433     }
1434 
1435     currentNumberFormat = getNumberFormatByIndex(patternCharIndex);
1436     if (currentNumberFormat == NULL) {
1437         status = U_INTERNAL_PROGRAM_ERROR;
1438         return;
1439     }
1440     UnicodeString hebr("hebr", 4, US_INV);
1441 
1442     switch (patternCharIndex) {
1443 
1444     // for any "G" symbol, write out the appropriate era string
1445     // "GGGG" is wide era name, "GGGGG" is narrow era name, anything else is abbreviated name
1446     case UDAT_ERA_FIELD:
1447         if (isChineseCalendar) {
1448             zeroPaddingNumber(currentNumberFormat,appendTo, value, 1, 9); // as in ICU4J
1449         } else {
1450             if (count == 5) {
1451                 _appendSymbol(appendTo, value, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount);
1452                 capContextUsageType = DateFormatSymbols::kCapContextUsageEraNarrow;
1453             } else if (count == 4) {
1454                 _appendSymbol(appendTo, value, fSymbols->fEraNames, fSymbols->fEraNamesCount);
1455                 capContextUsageType = DateFormatSymbols::kCapContextUsageEraWide;
1456             } else {
1457                 _appendSymbol(appendTo, value, fSymbols->fEras, fSymbols->fErasCount);
1458                 capContextUsageType = DateFormatSymbols::kCapContextUsageEraAbbrev;
1459             }
1460         }
1461         break;
1462 
1463      case UDAT_YEAR_NAME_FIELD:
1464         if (fSymbols->fShortYearNames != NULL && value <= fSymbols->fShortYearNamesCount) {
1465             // the Calendar YEAR field runs 1 through 60 for cyclic years
1466             _appendSymbol(appendTo, value - 1, fSymbols->fShortYearNames, fSymbols->fShortYearNamesCount);
1467             break;
1468         }
1469         // else fall through to numeric year handling, do not break here
1470         U_FALLTHROUGH;
1471 
1472    // OLD: for "yyyy", write out the whole year; for "yy", write out the last 2 digits
1473     // NEW: UTS#35:
1474 //Year         y     yy     yyy     yyyy     yyyyy
1475 //AD 1         1     01     001     0001     00001
1476 //AD 12       12     12     012     0012     00012
1477 //AD 123     123     23     123     0123     00123
1478 //AD 1234   1234     34    1234     1234     01234
1479 //AD 12345 12345     45   12345    12345     12345
1480     case UDAT_YEAR_FIELD:
1481     case UDAT_YEAR_WOY_FIELD:
1482         if (fDateOverride.compare(hebr)==0 && value>HEBREW_CAL_CUR_MILLENIUM_START_YEAR && value<HEBREW_CAL_CUR_MILLENIUM_END_YEAR) {
1483             value-=HEBREW_CAL_CUR_MILLENIUM_START_YEAR;
1484         }
1485         if(count == 2)
1486             zeroPaddingNumber(currentNumberFormat, appendTo, value, 2, 2);
1487         else
1488             zeroPaddingNumber(currentNumberFormat, appendTo, value, count, maxIntCount);
1489         break;
1490 
1491     // for "MMMM"/"LLLL", write out the whole month name, for "MMM"/"LLL", write out the month
1492     // abbreviation, for "M"/"L" or "MM"/"LL", write out the month as a number with the
1493     // appropriate number of digits
1494     // for "MMMMM"/"LLLLL", use the narrow form
1495     case UDAT_MONTH_FIELD:
1496     case UDAT_STANDALONE_MONTH_FIELD:
1497         if ( isHebrewCalendar ) {
1498            HebrewCalendar *hc = (HebrewCalendar*)&cal;
1499            if (hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value == 6 && count >= 3 )
1500                value = 13; // Show alternate form for Adar II in leap years in Hebrew calendar.
1501            if (!hc->isLeapYear(hc->get(UCAL_YEAR,status)) && value >= 6 && count < 3 )
1502                value--; // Adjust the month number down 1 in Hebrew non-leap years, i.e. Adar is 6, not 7.
1503         }
1504         {
1505             int32_t isLeapMonth = (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount)?
1506                         cal.get(UCAL_IS_LEAP_MONTH, status): 0;
1507             // should consolidate the next section by using arrays of pointers & counts for the right symbols...
1508             if (count == 5) {
1509                 if (patternCharIndex == UDAT_MONTH_FIELD) {
1510                     _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fNarrowMonths, fSymbols->fNarrowMonthsCount,
1511                             (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatNarrow]): NULL, status);
1512                 } else {
1513                     _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneNarrowMonths, fSymbols->fStandaloneNarrowMonthsCount,
1514                             (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneNarrow]): NULL, status);
1515                 }
1516                 capContextUsageType = DateFormatSymbols::kCapContextUsageMonthNarrow;
1517             } else if (count == 4) {
1518                 if (patternCharIndex == UDAT_MONTH_FIELD) {
1519                     _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fMonths, fSymbols->fMonthsCount,
1520                             (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatWide]): NULL, status);
1521                     capContextUsageType = DateFormatSymbols::kCapContextUsageMonthFormat;
1522                 } else {
1523                     _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneMonths, fSymbols->fStandaloneMonthsCount,
1524                             (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneWide]): NULL, status);
1525                     capContextUsageType = DateFormatSymbols::kCapContextUsageMonthStandalone;
1526                 }
1527             } else if (count == 3) {
1528                 if (patternCharIndex == UDAT_MONTH_FIELD) {
1529                     _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fShortMonths, fSymbols->fShortMonthsCount,
1530                             (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatAbbrev]): NULL, status);
1531                     capContextUsageType = DateFormatSymbols::kCapContextUsageMonthFormat;
1532                 } else {
1533                     _appendSymbolWithMonthPattern(appendTo, value, fSymbols->fStandaloneShortMonths, fSymbols->fStandaloneShortMonthsCount,
1534                             (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneAbbrev]): NULL, status);
1535                     capContextUsageType = DateFormatSymbols::kCapContextUsageMonthStandalone;
1536                 }
1537             } else {
1538                 UnicodeString monthNumber;
1539                 zeroPaddingNumber(currentNumberFormat,monthNumber, value + 1, count, maxIntCount);
1540                 _appendSymbolWithMonthPattern(appendTo, 0, &monthNumber, 1,
1541                         (isLeapMonth!=0)? &(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternNumeric]): NULL, status);
1542             }
1543         }
1544         break;
1545 
1546     // for "k" and "kk", write out the hour, adjusting midnight to appear as "24"
1547     case UDAT_HOUR_OF_DAY1_FIELD:
1548         if (value == 0)
1549             zeroPaddingNumber(currentNumberFormat,appendTo, cal.getMaximum(UCAL_HOUR_OF_DAY) + 1, count, maxIntCount);
1550         else
1551             zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
1552         break;
1553 
1554     case UDAT_FRACTIONAL_SECOND_FIELD:
1555         // Fractional seconds left-justify
1556         {
1557             int32_t minDigits = (count > 3) ? 3 : count;
1558             if (count == 1) {
1559                 value /= 100;
1560             } else if (count == 2) {
1561                 value /= 10;
1562             }
1563             zeroPaddingNumber(currentNumberFormat, appendTo, value, minDigits, maxIntCount);
1564             if (count > 3) {
1565                 zeroPaddingNumber(currentNumberFormat, appendTo, 0, count - 3, maxIntCount);
1566             }
1567         }
1568         break;
1569 
1570     // for "ee" or "e", use local numeric day-of-the-week
1571     // for "EEEEEE" or "eeeeee", write out the short day-of-the-week name
1572     // for "EEEEE" or "eeeee", write out the narrow day-of-the-week name
1573     // for "EEEE" or "eeee", write out the wide day-of-the-week name
1574     // for "EEE" or "EE" or "E" or "eee", write out the abbreviated day-of-the-week name
1575     case UDAT_DOW_LOCAL_FIELD:
1576         if ( count < 3 ) {
1577             zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
1578             break;
1579         }
1580         // fall through to EEEEE-EEE handling, but for that we don't want local day-of-week,
1581         // we want standard day-of-week, so first fix value to work for EEEEE-EEE.
1582         value = cal.get(UCAL_DAY_OF_WEEK, status);
1583         if (U_FAILURE(status)) {
1584             return;
1585         }
1586         // fall through, do not break here
1587         U_FALLTHROUGH;
1588     case UDAT_DAY_OF_WEEK_FIELD:
1589         if (count == 5) {
1590             _appendSymbol(appendTo, value, fSymbols->fNarrowWeekdays,
1591                           fSymbols->fNarrowWeekdaysCount);
1592             capContextUsageType = DateFormatSymbols::kCapContextUsageDayNarrow;
1593         } else if (count == 4) {
1594             _appendSymbol(appendTo, value, fSymbols->fWeekdays,
1595                           fSymbols->fWeekdaysCount);
1596             capContextUsageType = DateFormatSymbols::kCapContextUsageDayFormat;
1597         } else if (count == 6) {
1598             _appendSymbol(appendTo, value, fSymbols->fShorterWeekdays,
1599                           fSymbols->fShorterWeekdaysCount);
1600             capContextUsageType = DateFormatSymbols::kCapContextUsageDayFormat;
1601         } else {
1602             _appendSymbol(appendTo, value, fSymbols->fShortWeekdays,
1603                           fSymbols->fShortWeekdaysCount);
1604             capContextUsageType = DateFormatSymbols::kCapContextUsageDayFormat;
1605         }
1606         break;
1607 
1608     // for "ccc", write out the abbreviated day-of-the-week name
1609     // for "cccc", write out the wide day-of-the-week name
1610     // for "ccccc", use the narrow day-of-the-week name
1611     // for "ccccc", use the short day-of-the-week name
1612     case UDAT_STANDALONE_DAY_FIELD:
1613         if ( count < 3 ) {
1614             zeroPaddingNumber(currentNumberFormat,appendTo, value, 1, maxIntCount);
1615             break;
1616         }
1617         // fall through to alpha DOW handling, but for that we don't want local day-of-week,
1618         // we want standard day-of-week, so first fix value.
1619         value = cal.get(UCAL_DAY_OF_WEEK, status);
1620         if (U_FAILURE(status)) {
1621             return;
1622         }
1623         if (count == 5) {
1624             _appendSymbol(appendTo, value, fSymbols->fStandaloneNarrowWeekdays,
1625                           fSymbols->fStandaloneNarrowWeekdaysCount);
1626             capContextUsageType = DateFormatSymbols::kCapContextUsageDayNarrow;
1627         } else if (count == 4) {
1628             _appendSymbol(appendTo, value, fSymbols->fStandaloneWeekdays,
1629                           fSymbols->fStandaloneWeekdaysCount);
1630             capContextUsageType = DateFormatSymbols::kCapContextUsageDayStandalone;
1631         } else if (count == 6) {
1632             _appendSymbol(appendTo, value, fSymbols->fStandaloneShorterWeekdays,
1633                           fSymbols->fStandaloneShorterWeekdaysCount);
1634             capContextUsageType = DateFormatSymbols::kCapContextUsageDayStandalone;
1635         } else { // count == 3
1636             _appendSymbol(appendTo, value, fSymbols->fStandaloneShortWeekdays,
1637                           fSymbols->fStandaloneShortWeekdaysCount);
1638             capContextUsageType = DateFormatSymbols::kCapContextUsageDayStandalone;
1639         }
1640         break;
1641 
1642     // for "a" symbol, write out the whole AM/PM string
1643     case UDAT_AM_PM_FIELD:
1644         if (count < 5) {
1645             _appendSymbol(appendTo, value, fSymbols->fAmPms,
1646                           fSymbols->fAmPmsCount);
1647         } else {
1648             _appendSymbol(appendTo, value, fSymbols->fNarrowAmPms,
1649                           fSymbols->fNarrowAmPmsCount);
1650         }
1651         break;
1652 
1653     // if we see pattern character for UDAT_TIME_SEPARATOR_FIELD (none currently defined),
1654     // write out the time separator string. Leave support in for future definition.
1655     case UDAT_TIME_SEPARATOR_FIELD:
1656         {
1657             UnicodeString separator;
1658             appendTo += fSymbols->getTimeSeparatorString(separator);
1659         }
1660         break;
1661 
1662     // for "h" and "hh", write out the hour, adjusting noon and midnight to show up
1663     // as "12"
1664     case UDAT_HOUR1_FIELD:
1665         if (value == 0)
1666             zeroPaddingNumber(currentNumberFormat,appendTo, cal.getLeastMaximum(UCAL_HOUR) + 1, count, maxIntCount);
1667         else
1668             zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
1669         break;
1670 
1671     case UDAT_TIMEZONE_FIELD: // 'z'
1672     case UDAT_TIMEZONE_RFC_FIELD: // 'Z'
1673     case UDAT_TIMEZONE_GENERIC_FIELD: // 'v'
1674     case UDAT_TIMEZONE_SPECIAL_FIELD: // 'V'
1675     case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD: // 'O'
1676     case UDAT_TIMEZONE_ISO_FIELD: // 'X'
1677     case UDAT_TIMEZONE_ISO_LOCAL_FIELD: // 'x'
1678         {
1679             UChar zsbuf[ZONE_NAME_U16_MAX];
1680             UnicodeString zoneString(zsbuf, 0, UPRV_LENGTHOF(zsbuf));
1681             const TimeZone& tz = cal.getTimeZone();
1682             UDate date = cal.getTime(status);
1683             const TimeZoneFormat *tzfmt = tzFormat(status);
1684             if (U_SUCCESS(status)) {
1685                 if (patternCharIndex == UDAT_TIMEZONE_FIELD) {
1686                     if (count < 4) {
1687                         // "z", "zz", "zzz"
1688                         tzfmt->format(UTZFMT_STYLE_SPECIFIC_SHORT, tz, date, zoneString);
1689                         capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort;
1690                     } else {
1691                         // "zzzz" or longer
1692                         tzfmt->format(UTZFMT_STYLE_SPECIFIC_LONG, tz, date, zoneString);
1693                         capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneLong;
1694                     }
1695                 }
1696                 else if (patternCharIndex == UDAT_TIMEZONE_RFC_FIELD) {
1697                     if (count < 4) {
1698                         // "Z"
1699                         tzfmt->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, tz, date, zoneString);
1700                     } else if (count == 5) {
1701                         // "ZZZZZ"
1702                         tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString);
1703                     } else {
1704                         // "ZZ", "ZZZ", "ZZZZ"
1705                         tzfmt->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString);
1706                     }
1707                 }
1708                 else if (patternCharIndex == UDAT_TIMEZONE_GENERIC_FIELD) {
1709                     if (count == 1) {
1710                         // "v"
1711                         tzfmt->format(UTZFMT_STYLE_GENERIC_SHORT, tz, date, zoneString);
1712                         capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneShort;
1713                     } else if (count == 4) {
1714                         // "vvvv"
1715                         tzfmt->format(UTZFMT_STYLE_GENERIC_LONG, tz, date, zoneString);
1716                         capContextUsageType = DateFormatSymbols::kCapContextUsageMetazoneLong;
1717                     }
1718                 }
1719                 else if (patternCharIndex == UDAT_TIMEZONE_SPECIAL_FIELD) {
1720                     if (count == 1) {
1721                         // "V"
1722                         tzfmt->format(UTZFMT_STYLE_ZONE_ID_SHORT, tz, date, zoneString);
1723                     } else if (count == 2) {
1724                         // "VV"
1725                         tzfmt->format(UTZFMT_STYLE_ZONE_ID, tz, date, zoneString);
1726                     } else if (count == 3) {
1727                         // "VVV"
1728                         tzfmt->format(UTZFMT_STYLE_EXEMPLAR_LOCATION, tz, date, zoneString);
1729                     } else if (count == 4) {
1730                         // "VVVV"
1731                         tzfmt->format(UTZFMT_STYLE_GENERIC_LOCATION, tz, date, zoneString);
1732                         capContextUsageType = DateFormatSymbols::kCapContextUsageZoneLong;
1733                     }
1734                 }
1735                 else if (patternCharIndex == UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD) {
1736                     if (count == 1) {
1737                         // "O"
1738                         tzfmt->format(UTZFMT_STYLE_LOCALIZED_GMT_SHORT, tz, date, zoneString);
1739                     } else if (count == 4) {
1740                         // "OOOO"
1741                         tzfmt->format(UTZFMT_STYLE_LOCALIZED_GMT, tz, date, zoneString);
1742                     }
1743                 }
1744                 else if (patternCharIndex == UDAT_TIMEZONE_ISO_FIELD) {
1745                     if (count == 1) {
1746                         // "X"
1747                         tzfmt->format(UTZFMT_STYLE_ISO_BASIC_SHORT, tz, date, zoneString);
1748                     } else if (count == 2) {
1749                         // "XX"
1750                         tzfmt->format(UTZFMT_STYLE_ISO_BASIC_FIXED, tz, date, zoneString);
1751                     } else if (count == 3) {
1752                         // "XXX"
1753                         tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_FIXED, tz, date, zoneString);
1754                     } else if (count == 4) {
1755                         // "XXXX"
1756                         tzfmt->format(UTZFMT_STYLE_ISO_BASIC_FULL, tz, date, zoneString);
1757                     } else if (count == 5) {
1758                         // "XXXXX"
1759                         tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_FULL, tz, date, zoneString);
1760                     }
1761                 }
1762                 else if (patternCharIndex == UDAT_TIMEZONE_ISO_LOCAL_FIELD) {
1763                     if (count == 1) {
1764                         // "x"
1765                         tzfmt->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_SHORT, tz, date, zoneString);
1766                     } else if (count == 2) {
1767                         // "xx"
1768                         tzfmt->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FIXED, tz, date, zoneString);
1769                     } else if (count == 3) {
1770                         // "xxx"
1771                         tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FIXED, tz, date, zoneString);
1772                     } else if (count == 4) {
1773                         // "xxxx"
1774                         tzfmt->format(UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL, tz, date, zoneString);
1775                     } else if (count == 5) {
1776                         // "xxxxx"
1777                         tzfmt->format(UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL, tz, date, zoneString);
1778                     }
1779                 }
1780                 else {
1781                     U_ASSERT(FALSE);
1782                 }
1783             }
1784             appendTo += zoneString;
1785         }
1786         break;
1787 
1788     case UDAT_QUARTER_FIELD:
1789         if (count >= 4)
1790             _appendSymbol(appendTo, value/3, fSymbols->fQuarters,
1791                           fSymbols->fQuartersCount);
1792         else if (count == 3)
1793             _appendSymbol(appendTo, value/3, fSymbols->fShortQuarters,
1794                           fSymbols->fShortQuartersCount);
1795         else
1796             zeroPaddingNumber(currentNumberFormat,appendTo, (value/3) + 1, count, maxIntCount);
1797         break;
1798 
1799     case UDAT_STANDALONE_QUARTER_FIELD:
1800         if (count >= 4)
1801             _appendSymbol(appendTo, value/3, fSymbols->fStandaloneQuarters,
1802                           fSymbols->fStandaloneQuartersCount);
1803         else if (count == 3)
1804             _appendSymbol(appendTo, value/3, fSymbols->fStandaloneShortQuarters,
1805                           fSymbols->fStandaloneShortQuartersCount);
1806         else
1807             zeroPaddingNumber(currentNumberFormat,appendTo, (value/3) + 1, count, maxIntCount);
1808         break;
1809 
1810     case UDAT_AM_PM_MIDNIGHT_NOON_FIELD:
1811     {
1812         const UnicodeString *toAppend = NULL;
1813         int32_t hour = cal.get(UCAL_HOUR_OF_DAY, status);
1814 
1815         // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
1816         // For ICU 57 output of "midnight" is temporarily suppressed.
1817 
1818         // For "midnight" and "noon":
1819         // Time, as displayed, must be exactly noon or midnight.
1820         // This means minutes and seconds, if present, must be zero.
1821         if ((/*hour == 0 ||*/ hour == 12) &&
1822                 (!fHasMinute || cal.get(UCAL_MINUTE, status) == 0) &&
1823                 (!fHasSecond || cal.get(UCAL_SECOND, status) == 0)) {
1824             // Stealing am/pm value to use as our array index.
1825             // It works out: am/midnight are both 0, pm/noon are both 1,
1826             // 12 am is 12 midnight, and 12 pm is 12 noon.
1827             int32_t val = cal.get(UCAL_AM_PM, status);
1828 
1829             if (count <= 3) {
1830                 toAppend = &fSymbols->fAbbreviatedDayPeriods[val];
1831             } else if (count == 4 || count > 5) {
1832                 toAppend = &fSymbols->fWideDayPeriods[val];
1833             } else { // count == 5
1834                 toAppend = &fSymbols->fNarrowDayPeriods[val];
1835             }
1836         }
1837 
1838         // toAppend is NULL if time isn't exactly midnight or noon (as displayed).
1839         // toAppend is bogus if time is midnight or noon, but no localized string exists.
1840         // In either case, fall back to am/pm.
1841         if (toAppend == NULL || toAppend->isBogus()) {
1842             // Reformat with identical arguments except ch, now changed to 'a'.
1843             subFormat(appendTo, 0x61, count, capitalizationContext, fieldNum,
1844                       handler, cal, status);
1845         } else {
1846             appendTo += *toAppend;
1847         }
1848 
1849         break;
1850     }
1851 
1852     case UDAT_FLEXIBLE_DAY_PERIOD_FIELD:
1853     {
1854         // TODO: Maybe fetch the DayperiodRules during initialization (instead of at the first
1855         // loading of an instance) if a relevant pattern character (b or B) is used.
1856         const DayPeriodRules *ruleSet = DayPeriodRules::getInstance(this->getSmpFmtLocale(), status);
1857         if (U_FAILURE(status)) {
1858             // Data doesn't conform to spec, therefore loading failed.
1859             break;
1860         }
1861         if (ruleSet == NULL) {
1862             // Data doesn't exist for the locale we're looking for.
1863             // Falling back to am/pm.
1864             subFormat(appendTo, 0x61, count, capitalizationContext, fieldNum,
1865                       handler, cal, status);
1866             break;
1867         }
1868 
1869         // Get current display time.
1870         int32_t hour = cal.get(UCAL_HOUR_OF_DAY, status);
1871         int32_t minute = 0;
1872         if (fHasMinute) {
1873             minute = cal.get(UCAL_MINUTE, status);
1874         }
1875         int32_t second = 0;
1876         if (fHasSecond) {
1877             second = cal.get(UCAL_SECOND, status);
1878         }
1879 
1880         // Determine day period.
1881         DayPeriodRules::DayPeriod periodType;
1882         if (hour == 0 && minute == 0 && second == 0 && ruleSet->hasMidnight()) {
1883             periodType = DayPeriodRules::DAYPERIOD_MIDNIGHT;
1884         } else if (hour == 12 && minute == 0 && second == 0 && ruleSet->hasNoon()) {
1885             periodType = DayPeriodRules::DAYPERIOD_NOON;
1886         } else {
1887             periodType = ruleSet->getDayPeriodForHour(hour);
1888         }
1889 
1890         // Rule set exists, therefore periodType can't be UNKNOWN.
1891         // Get localized string.
1892         U_ASSERT(periodType != DayPeriodRules::DAYPERIOD_UNKNOWN);
1893         UnicodeString *toAppend = NULL;
1894         int32_t index;
1895 
1896         // Note: "midnight" can be ambiguous as to whether it refers to beginning of day or end of day.
1897         // For ICU 57 output of "midnight" is temporarily suppressed.
1898 
1899         if (periodType != DayPeriodRules::DAYPERIOD_AM &&
1900                 periodType != DayPeriodRules::DAYPERIOD_PM &&
1901                 periodType != DayPeriodRules::DAYPERIOD_MIDNIGHT) {
1902             index = (int32_t)periodType;
1903             if (count <= 3) {
1904                 toAppend = &fSymbols->fAbbreviatedDayPeriods[index];  // i.e. short
1905             } else if (count == 4 || count > 5) {
1906                 toAppend = &fSymbols->fWideDayPeriods[index];
1907             } else {  // count == 5
1908                 toAppend = &fSymbols->fNarrowDayPeriods[index];
1909             }
1910         }
1911 
1912         // Fallback schedule:
1913         // Midnight/Noon -> General Periods -> AM/PM.
1914 
1915         // Midnight/Noon -> General Periods.
1916         if ((toAppend == NULL || toAppend->isBogus()) &&
1917                 (periodType == DayPeriodRules::DAYPERIOD_MIDNIGHT ||
1918                  periodType == DayPeriodRules::DAYPERIOD_NOON)) {
1919             periodType = ruleSet->getDayPeriodForHour(hour);
1920             index = (int32_t)periodType;
1921 
1922             if (count <= 3) {
1923                 toAppend = &fSymbols->fAbbreviatedDayPeriods[index];  // i.e. short
1924             } else if (count == 4 || count > 5) {
1925                 toAppend = &fSymbols->fWideDayPeriods[index];
1926             } else {  // count == 5
1927                 toAppend = &fSymbols->fNarrowDayPeriods[index];
1928             }
1929         }
1930 
1931         // General Periods -> AM/PM.
1932         if (periodType == DayPeriodRules::DAYPERIOD_AM ||
1933             periodType == DayPeriodRules::DAYPERIOD_PM ||
1934             toAppend->isBogus()) {
1935             subFormat(appendTo, 0x61, count, capitalizationContext, fieldNum,
1936                       handler, cal, status);
1937         }
1938         else {
1939             appendTo += *toAppend;
1940         }
1941 
1942         break;
1943     }
1944 
1945     // all of the other pattern symbols can be formatted as simple numbers with
1946     // appropriate zero padding
1947     default:
1948         zeroPaddingNumber(currentNumberFormat,appendTo, value, count, maxIntCount);
1949         break;
1950     }
1951 #if !UCONFIG_NO_BREAK_ITERATION
1952     // if first field, check to see whether we need to and are able to titlecase it
1953     if (fieldNum == 0 && u_islower(appendTo.char32At(beginOffset)) && fCapitalizationBrkIter != NULL) {
1954         UBool titlecase = FALSE;
1955         switch (capitalizationContext) {
1956             case UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE:
1957                 titlecase = TRUE;
1958                 break;
1959             case UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU:
1960                 titlecase = fSymbols->fCapitalization[capContextUsageType][0];
1961                 break;
1962             case UDISPCTX_CAPITALIZATION_FOR_STANDALONE:
1963                 titlecase = fSymbols->fCapitalization[capContextUsageType][1];
1964                 break;
1965             default:
1966                 // titlecase = FALSE;
1967                 break;
1968         }
1969         if (titlecase) {
1970             UnicodeString firstField(appendTo, beginOffset);
1971             firstField.toTitle(fCapitalizationBrkIter, fLocale, U_TITLECASE_NO_LOWERCASE | U_TITLECASE_NO_BREAK_ADJUSTMENT);
1972             appendTo.replaceBetween(beginOffset, appendTo.length(), firstField);
1973         }
1974     }
1975 #endif
1976 
1977     handler.addAttribute(fgPatternIndexToDateFormatField[patternCharIndex], beginOffset, appendTo.length());
1978 }
1979 
1980 //----------------------------------------------------------------------
1981 
adoptNumberFormat(NumberFormat * formatToAdopt)1982 void SimpleDateFormat::adoptNumberFormat(NumberFormat *formatToAdopt) {
1983     fixNumberFormatForDates(*formatToAdopt);
1984     delete fNumberFormat;
1985     fNumberFormat = formatToAdopt;
1986 
1987     // We successfully set the default number format. Now delete the overrides
1988     // (can't fail).
1989     if (fSharedNumberFormatters) {
1990         freeSharedNumberFormatters(fSharedNumberFormatters);
1991         fSharedNumberFormatters = NULL;
1992     }
1993 
1994     // Also re-compute the fast formatters.
1995     UErrorCode localStatus = U_ZERO_ERROR;
1996     freeFastNumberFormatters();
1997     initFastNumberFormatters(localStatus);
1998 }
1999 
adoptNumberFormat(const UnicodeString & fields,NumberFormat * formatToAdopt,UErrorCode & status)2000 void SimpleDateFormat::adoptNumberFormat(const UnicodeString& fields, NumberFormat *formatToAdopt, UErrorCode &status){
2001     fixNumberFormatForDates(*formatToAdopt);
2002     LocalPointer<NumberFormat> fmt(formatToAdopt);
2003     if (U_FAILURE(status)) {
2004         return;
2005     }
2006 
2007     // We must ensure fSharedNumberFormatters is allocated.
2008     if (fSharedNumberFormatters == NULL) {
2009         fSharedNumberFormatters = allocSharedNumberFormatters();
2010         if (fSharedNumberFormatters == NULL) {
2011             status = U_MEMORY_ALLOCATION_ERROR;
2012             return;
2013         }
2014     }
2015     const SharedNumberFormat *newFormat = createSharedNumberFormat(fmt.orphan());
2016     if (newFormat == NULL) {
2017         status = U_MEMORY_ALLOCATION_ERROR;
2018         return;
2019     }
2020     for (int i=0; i<fields.length(); i++) {
2021         UChar field = fields.charAt(i);
2022         // if the pattern character is unrecognized, signal an error and bail out
2023         UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(field);
2024         if (patternCharIndex == UDAT_FIELD_COUNT) {
2025             status = U_INVALID_FORMAT_ERROR;
2026             newFormat->deleteIfZeroRefCount();
2027             return;
2028         }
2029 
2030         // Set the number formatter in the table
2031         SharedObject::copyPtr(
2032                 newFormat, fSharedNumberFormatters[patternCharIndex]);
2033     }
2034     newFormat->deleteIfZeroRefCount();
2035 }
2036 
2037 const NumberFormat *
getNumberFormatForField(UChar field) const2038 SimpleDateFormat::getNumberFormatForField(UChar field) const {
2039     UDateFormatField index = DateFormatSymbols::getPatternCharIndex(field);
2040     if (index == UDAT_FIELD_COUNT) {
2041         return NULL;
2042     }
2043     return getNumberFormatByIndex(index);
2044 }
2045 
2046 //----------------------------------------------------------------------
2047 void
zeroPaddingNumber(const NumberFormat * currentNumberFormat,UnicodeString & appendTo,int32_t value,int32_t minDigits,int32_t maxDigits) const2048 SimpleDateFormat::zeroPaddingNumber(
2049         const NumberFormat *currentNumberFormat,
2050         UnicodeString &appendTo,
2051         int32_t value, int32_t minDigits, int32_t maxDigits) const
2052 {
2053     const number::LocalizedNumberFormatter* fastFormatter = nullptr;
2054     // NOTE: This uses the heuristic that these five min/max int settings account for the vast majority
2055     // of SimpleDateFormat number formatting cases at the time of writing (ICU 62).
2056     if (currentNumberFormat == fNumberFormat) {
2057         if (maxDigits == 10) {
2058             if (minDigits == 1) {
2059                 fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_1x10];
2060             } else if (minDigits == 2) {
2061                 fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_2x10];
2062             } else if (minDigits == 3) {
2063                 fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_3x10];
2064             } else if (minDigits == 4) {
2065                 fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_4x10];
2066             }
2067         } else if (maxDigits == 2) {
2068             if (minDigits == 2) {
2069                 fastFormatter = fFastNumberFormatters[SMPDTFMT_NF_2x2];
2070             }
2071         }
2072     }
2073     if (fastFormatter != nullptr) {
2074         // Can use fast path
2075         number::impl::UFormattedNumberData result;
2076         result.quantity.setToInt(value);
2077         UErrorCode localStatus = U_ZERO_ERROR;
2078         fastFormatter->formatImpl(&result, localStatus);
2079         if (U_FAILURE(localStatus)) {
2080             return;
2081         }
2082         appendTo.append(result.string.toTempUnicodeString());
2083         return;
2084     }
2085 
2086     // Check for RBNF (no clone necessary)
2087     auto* rbnf = dynamic_cast<const RuleBasedNumberFormat*>(currentNumberFormat);
2088     if (rbnf != nullptr) {
2089         FieldPosition pos(FieldPosition::DONT_CARE);
2090         rbnf->format(value, appendTo, pos);  // 3rd arg is there to speed up processing
2091         return;
2092     }
2093 
2094     // Fall back to slow path (clone and mutate the NumberFormat)
2095     if (currentNumberFormat != nullptr) {
2096         FieldPosition pos(FieldPosition::DONT_CARE);
2097         LocalPointer<NumberFormat> nf(dynamic_cast<NumberFormat*>(currentNumberFormat->clone()));
2098         nf->setMinimumIntegerDigits(minDigits);
2099         nf->setMaximumIntegerDigits(maxDigits);
2100         nf->format(value, appendTo, pos);  // 3rd arg is there to speed up processing
2101     }
2102 }
2103 
2104 //----------------------------------------------------------------------
2105 
2106 /**
2107  * Return true if the given format character, occuring count
2108  * times, represents a numeric field.
2109  */
isNumeric(UChar formatChar,int32_t count)2110 UBool SimpleDateFormat::isNumeric(UChar formatChar, int32_t count) {
2111     return DateFormatSymbols::isNumericPatternChar(formatChar, count);
2112 }
2113 
2114 UBool
isAtNumericField(const UnicodeString & pattern,int32_t patternOffset)2115 SimpleDateFormat::isAtNumericField(const UnicodeString &pattern, int32_t patternOffset) {
2116     if (patternOffset >= pattern.length()) {
2117         // not at any field
2118         return FALSE;
2119     }
2120     UChar ch = pattern.charAt(patternOffset);
2121     UDateFormatField f = DateFormatSymbols::getPatternCharIndex(ch);
2122     if (f == UDAT_FIELD_COUNT) {
2123         // not at any field
2124         return FALSE;
2125     }
2126     int32_t i = patternOffset;
2127     while (pattern.charAt(++i) == ch) {}
2128     return DateFormatSymbols::isNumericField(f, i - patternOffset);
2129 }
2130 
2131 UBool
isAfterNonNumericField(const UnicodeString & pattern,int32_t patternOffset)2132 SimpleDateFormat::isAfterNonNumericField(const UnicodeString &pattern, int32_t patternOffset) {
2133     if (patternOffset <= 0) {
2134         // not after any field
2135         return FALSE;
2136     }
2137     UChar ch = pattern.charAt(--patternOffset);
2138     UDateFormatField f = DateFormatSymbols::getPatternCharIndex(ch);
2139     if (f == UDAT_FIELD_COUNT) {
2140         // not after any field
2141         return FALSE;
2142     }
2143     int32_t i = patternOffset;
2144     while (pattern.charAt(--i) == ch) {}
2145     return !DateFormatSymbols::isNumericField(f, patternOffset - i);
2146 }
2147 
2148 void
parse(const UnicodeString & text,Calendar & cal,ParsePosition & parsePos) const2149 SimpleDateFormat::parse(const UnicodeString& text, Calendar& cal, ParsePosition& parsePos) const
2150 {
2151     UErrorCode status = U_ZERO_ERROR;
2152     int32_t pos = parsePos.getIndex();
2153     if(parsePos.getIndex() < 0) {
2154         parsePos.setErrorIndex(0);
2155         return;
2156     }
2157     int32_t start = pos;
2158 
2159     // Hold the day period until everything else is parsed, because we need
2160     // the hour to interpret time correctly.
2161     int32_t dayPeriodInt = -1;
2162 
2163     UBool ambiguousYear[] = { FALSE };
2164     int32_t saveHebrewMonth = -1;
2165     int32_t count = 0;
2166     UTimeZoneFormatTimeType tzTimeType = UTZFMT_TIME_TYPE_UNKNOWN;
2167 
2168     // For parsing abutting numeric fields. 'abutPat' is the
2169     // offset into 'pattern' of the first of 2 or more abutting
2170     // numeric fields.  'abutStart' is the offset into 'text'
2171     // where parsing the fields begins. 'abutPass' starts off as 0
2172     // and increments each time we try to parse the fields.
2173     int32_t abutPat = -1; // If >=0, we are in a run of abutting numeric fields
2174     int32_t abutStart = 0;
2175     int32_t abutPass = 0;
2176     UBool inQuote = FALSE;
2177 
2178     MessageFormat * numericLeapMonthFormatter = NULL;
2179 
2180     Calendar* calClone = NULL;
2181     Calendar *workCal = &cal;
2182     if (&cal != fCalendar && uprv_strcmp(cal.getType(), fCalendar->getType()) != 0) {
2183         // Different calendar type
2184         // We use the time/zone from the input calendar, but
2185         // do not use the input calendar for field calculation.
2186         calClone = fCalendar->clone();
2187         if (calClone != NULL) {
2188             calClone->setTime(cal.getTime(status),status);
2189             if (U_FAILURE(status)) {
2190                 goto ExitParse;
2191             }
2192             calClone->setTimeZone(cal.getTimeZone());
2193             workCal = calClone;
2194         } else {
2195             status = U_MEMORY_ALLOCATION_ERROR;
2196             goto ExitParse;
2197         }
2198     }
2199 
2200     if (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount) {
2201         numericLeapMonthFormatter = new MessageFormat(fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternNumeric], fLocale, status);
2202         if (numericLeapMonthFormatter == NULL) {
2203              status = U_MEMORY_ALLOCATION_ERROR;
2204              goto ExitParse;
2205         } else if (U_FAILURE(status)) {
2206              goto ExitParse; // this will delete numericLeapMonthFormatter
2207         }
2208     }
2209 
2210     for (int32_t i=0; i<fPattern.length(); ++i) {
2211         UChar ch = fPattern.charAt(i);
2212 
2213         // Handle alphabetic field characters.
2214         if (!inQuote && isSyntaxChar(ch)) {
2215             int32_t fieldPat = i;
2216 
2217             // Count the length of this field specifier
2218             count = 1;
2219             while ((i+1)<fPattern.length() &&
2220                    fPattern.charAt(i+1) == ch) {
2221                 ++count;
2222                 ++i;
2223             }
2224 
2225             if (isNumeric(ch, count)) {
2226                 if (abutPat < 0) {
2227                     // Determine if there is an abutting numeric field.
2228                     // Record the start of a set of abutting numeric fields.
2229                     if (isAtNumericField(fPattern, i + 1)) {
2230                         abutPat = fieldPat;
2231                         abutStart = pos;
2232                         abutPass = 0;
2233                     }
2234                 }
2235             } else {
2236                 abutPat = -1; // End of any abutting fields
2237             }
2238 
2239             // Handle fields within a run of abutting numeric fields.  Take
2240             // the pattern "HHmmss" as an example. We will try to parse
2241             // 2/2/2 characters of the input text, then if that fails,
2242             // 1/2/2.  We only adjust the width of the leftmost field; the
2243             // others remain fixed.  This allows "123456" => 12:34:56, but
2244             // "12345" => 1:23:45.  Likewise, for the pattern "yyyyMMdd" we
2245             // try 4/2/2, 3/2/2, 2/2/2, and finally 1/2/2.
2246             if (abutPat >= 0) {
2247                 // If we are at the start of a run of abutting fields, then
2248                 // shorten this field in each pass.  If we can't shorten
2249                 // this field any more, then the parse of this set of
2250                 // abutting numeric fields has failed.
2251                 if (fieldPat == abutPat) {
2252                     count -= abutPass++;
2253                     if (count == 0) {
2254                         status = U_PARSE_ERROR;
2255                         goto ExitParse;
2256                     }
2257                 }
2258 
2259                 pos = subParse(text, pos, ch, count,
2260                                TRUE, FALSE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType);
2261 
2262                 // If the parse fails anywhere in the run, back up to the
2263                 // start of the run and retry.
2264                 if (pos < 0) {
2265                     i = abutPat - 1;
2266                     pos = abutStart;
2267                     continue;
2268                 }
2269             }
2270 
2271             // Handle non-numeric fields and non-abutting numeric
2272             // fields.
2273             else if (ch != 0x6C) { // pattern char 'l' (SMALL LETTER L) just gets ignored
2274                 int32_t s = subParse(text, pos, ch, count,
2275                                FALSE, TRUE, ambiguousYear, saveHebrewMonth, *workCal, i, numericLeapMonthFormatter, &tzTimeType, &dayPeriodInt);
2276 
2277                 if (s == -pos-1) {
2278                     // era not present, in special cases allow this to continue
2279                     // from the position where the era was expected
2280                     s = pos;
2281 
2282                     if (i+1 < fPattern.length()) {
2283                         // move to next pattern character
2284                         UChar c = fPattern.charAt(i+1);
2285 
2286                         // check for whitespace
2287                         if (PatternProps::isWhiteSpace(c)) {
2288                             i++;
2289                             // Advance over run in pattern
2290                             while ((i+1)<fPattern.length() &&
2291                                    PatternProps::isWhiteSpace(fPattern.charAt(i+1))) {
2292                                 ++i;
2293                             }
2294                         }
2295                     }
2296                 }
2297                 else if (s <= 0) {
2298                     status = U_PARSE_ERROR;
2299                     goto ExitParse;
2300                 }
2301                 pos = s;
2302             }
2303         }
2304 
2305         // Handle literal pattern characters.  These are any
2306         // quoted characters and non-alphabetic unquoted
2307         // characters.
2308         else {
2309 
2310             abutPat = -1; // End of any abutting fields
2311 
2312             if (! matchLiterals(fPattern, i, text, pos, getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status), getBooleanAttribute(UDAT_PARSE_PARTIAL_LITERAL_MATCH, status), isLenient())) {
2313                 status = U_PARSE_ERROR;
2314                 goto ExitParse;
2315             }
2316         }
2317     }
2318 
2319     // Special hack for trailing "." after non-numeric field.
2320     if (text.charAt(pos) == 0x2e && getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status)) {
2321         // only do if the last field is not numeric
2322         if (isAfterNonNumericField(fPattern, fPattern.length())) {
2323             pos++; // skip the extra "."
2324         }
2325     }
2326 
2327     // If dayPeriod is set, use it in conjunction with hour-of-day to determine am/pm.
2328     if (dayPeriodInt >= 0) {
2329         DayPeriodRules::DayPeriod dayPeriod = (DayPeriodRules::DayPeriod)dayPeriodInt;
2330         const DayPeriodRules *ruleSet = DayPeriodRules::getInstance(this->getSmpFmtLocale(), status);
2331 
2332         if (!cal.isSet(UCAL_HOUR) && !cal.isSet(UCAL_HOUR_OF_DAY)) {
2333             // If hour is not set, set time to the midpoint of current day period, overwriting
2334             // minutes if it's set.
2335             double midPoint = ruleSet->getMidPointForDayPeriod(dayPeriod, status);
2336 
2337             // If we can't get midPoint we do nothing.
2338             if (U_SUCCESS(status)) {
2339                 // Truncate midPoint toward zero to get the hour.
2340                 // Any leftover means it was a half-hour.
2341                 int32_t midPointHour = (int32_t) midPoint;
2342                 int32_t midPointMinute = (midPoint - midPointHour) > 0 ? 30 : 0;
2343 
2344                 // No need to set am/pm because hour-of-day is set last therefore takes precedence.
2345                 cal.set(UCAL_HOUR_OF_DAY, midPointHour);
2346                 cal.set(UCAL_MINUTE, midPointMinute);
2347             }
2348         } else {
2349             int hourOfDay;
2350 
2351             if (cal.isSet(UCAL_HOUR_OF_DAY)) {  // Hour is parsed in 24-hour format.
2352                 hourOfDay = cal.get(UCAL_HOUR_OF_DAY, status);
2353             } else {  // Hour is parsed in 12-hour format.
2354                 hourOfDay = cal.get(UCAL_HOUR, status);
2355                 // cal.get() turns 12 to 0 for 12-hour time; change 0 to 12
2356                 // so 0 unambiguously means a 24-hour time from above.
2357                 if (hourOfDay == 0) { hourOfDay = 12; }
2358             }
2359             U_ASSERT(0 <= hourOfDay && hourOfDay <= 23);
2360 
2361 
2362             // If hour-of-day is 0 or 13 thru 23 then input time in unambiguously in 24-hour format.
2363             if (hourOfDay == 0 || (13 <= hourOfDay && hourOfDay <= 23)) {
2364                 // Make hour-of-day take precedence over (hour + am/pm) by setting it again.
2365                 cal.set(UCAL_HOUR_OF_DAY, hourOfDay);
2366             } else {
2367                 // We have a 12-hour time and need to choose between am and pm.
2368                 // Behave as if dayPeriod spanned 6 hours each way from its center point.
2369                 // This will parse correctly for consistent time + period (e.g. 10 at night) as
2370                 // well as provide a reasonable recovery for inconsistent time + period (e.g.
2371                 // 9 in the afternoon).
2372 
2373                 // Assume current time is in the AM.
2374                 // - Change 12 back to 0 for easier handling of 12am.
2375                 // - Append minutes as fractional hours because e.g. 8:15 and 8:45 could be parsed
2376                 // into different half-days if center of dayPeriod is at 14:30.
2377                 // - cal.get(MINUTE) will return 0 if MINUTE is unset, which works.
2378                 if (hourOfDay == 12) { hourOfDay = 0; }
2379                 double currentHour = hourOfDay + (cal.get(UCAL_MINUTE, status)) / 60.0;
2380                 double midPointHour = ruleSet->getMidPointForDayPeriod(dayPeriod, status);
2381 
2382                 if (U_SUCCESS(status)) {
2383                     double hoursAheadMidPoint = currentHour - midPointHour;
2384 
2385                     // Assume current time is in the AM.
2386                     if (-6 <= hoursAheadMidPoint && hoursAheadMidPoint < 6) {
2387                         // Assumption holds; set time as such.
2388                         cal.set(UCAL_AM_PM, 0);
2389                     } else {
2390                         cal.set(UCAL_AM_PM, 1);
2391                     }
2392                 }
2393             }
2394         }
2395     }
2396 
2397     // At this point the fields of Calendar have been set.  Calendar
2398     // will fill in default values for missing fields when the time
2399     // is computed.
2400 
2401     parsePos.setIndex(pos);
2402 
2403     // This part is a problem:  When we call parsedDate.after, we compute the time.
2404     // Take the date April 3 2004 at 2:30 am.  When this is first set up, the year
2405     // will be wrong if we're parsing a 2-digit year pattern.  It will be 1904.
2406     // April 3 1904 is a Sunday (unlike 2004) so it is the DST onset day.  2:30 am
2407     // is therefore an "impossible" time, since the time goes from 1:59 to 3:00 am
2408     // on that day.  It is therefore parsed out to fields as 3:30 am.  Then we
2409     // add 100 years, and get April 3 2004 at 3:30 am.  Note that April 3 2004 is
2410     // a Saturday, so it can have a 2:30 am -- and it should. [LIU]
2411     /*
2412         UDate parsedDate = calendar.getTime();
2413         if( ambiguousYear[0] && !parsedDate.after(fDefaultCenturyStart) ) {
2414             calendar.add(Calendar.YEAR, 100);
2415             parsedDate = calendar.getTime();
2416         }
2417     */
2418     // Because of the above condition, save off the fields in case we need to readjust.
2419     // The procedure we use here is not particularly efficient, but there is no other
2420     // way to do this given the API restrictions present in Calendar.  We minimize
2421     // inefficiency by only performing this computation when it might apply, that is,
2422     // when the two-digit year is equal to the start year, and thus might fall at the
2423     // front or the back of the default century.  This only works because we adjust
2424     // the year correctly to start with in other cases -- see subParse().
2425     if (ambiguousYear[0] || tzTimeType != UTZFMT_TIME_TYPE_UNKNOWN) // If this is true then the two-digit year == the default start year
2426     {
2427         // We need a copy of the fields, and we need to avoid triggering a call to
2428         // complete(), which will recalculate the fields.  Since we can't access
2429         // the fields[] array in Calendar, we clone the entire object.  This will
2430         // stop working if Calendar.clone() is ever rewritten to call complete().
2431         Calendar *copy;
2432         if (ambiguousYear[0]) {
2433             copy = cal.clone();
2434             // Check for failed cloning.
2435             if (copy == NULL) {
2436                 status = U_MEMORY_ALLOCATION_ERROR;
2437                 goto ExitParse;
2438             }
2439             UDate parsedDate = copy->getTime(status);
2440             // {sfb} check internalGetDefaultCenturyStart
2441             if (fHaveDefaultCentury && (parsedDate < fDefaultCenturyStart)) {
2442                 // We can't use add here because that does a complete() first.
2443                 cal.set(UCAL_YEAR, fDefaultCenturyStartYear + 100);
2444             }
2445             delete copy;
2446         }
2447 
2448         if (tzTimeType != UTZFMT_TIME_TYPE_UNKNOWN) {
2449             copy = cal.clone();
2450             // Check for failed cloning.
2451             if (copy == NULL) {
2452                 status = U_MEMORY_ALLOCATION_ERROR;
2453                 goto ExitParse;
2454             }
2455             const TimeZone & tz = cal.getTimeZone();
2456             BasicTimeZone *btz = NULL;
2457 
2458             if (dynamic_cast<const OlsonTimeZone *>(&tz) != NULL
2459                 || dynamic_cast<const SimpleTimeZone *>(&tz) != NULL
2460                 || dynamic_cast<const RuleBasedTimeZone *>(&tz) != NULL
2461                 || dynamic_cast<const VTimeZone *>(&tz) != NULL) {
2462                 btz = (BasicTimeZone*)&tz;
2463             }
2464 
2465             // Get local millis
2466             copy->set(UCAL_ZONE_OFFSET, 0);
2467             copy->set(UCAL_DST_OFFSET, 0);
2468             UDate localMillis = copy->getTime(status);
2469 
2470             // Make sure parsed time zone type (Standard or Daylight)
2471             // matches the rule used by the parsed time zone.
2472             int32_t raw, dst;
2473             if (btz != NULL) {
2474                 if (tzTimeType == UTZFMT_TIME_TYPE_STANDARD) {
2475                     btz->getOffsetFromLocal(localMillis,
2476                         BasicTimeZone::kStandard, BasicTimeZone::kStandard, raw, dst, status);
2477                 } else {
2478                     btz->getOffsetFromLocal(localMillis,
2479                         BasicTimeZone::kDaylight, BasicTimeZone::kDaylight, raw, dst, status);
2480                 }
2481             } else {
2482                 // No good way to resolve ambiguous time at transition,
2483                 // but following code work in most case.
2484                 tz.getOffset(localMillis, TRUE, raw, dst, status);
2485             }
2486 
2487             // Now, compare the results with parsed type, either standard or daylight saving time
2488             int32_t resolvedSavings = dst;
2489             if (tzTimeType == UTZFMT_TIME_TYPE_STANDARD) {
2490                 if (dst != 0) {
2491                     // Override DST_OFFSET = 0 in the result calendar
2492                     resolvedSavings = 0;
2493                 }
2494             } else { // tztype == TZTYPE_DST
2495                 if (dst == 0) {
2496                     if (btz != NULL) {
2497                         UDate time = localMillis + raw;
2498                         // We use the nearest daylight saving time rule.
2499                         TimeZoneTransition beforeTrs, afterTrs;
2500                         UDate beforeT = time, afterT = time;
2501                         int32_t beforeSav = 0, afterSav = 0;
2502                         UBool beforeTrsAvail, afterTrsAvail;
2503 
2504                         // Search for DST rule before or on the time
2505                         while (TRUE) {
2506                             beforeTrsAvail = btz->getPreviousTransition(beforeT, TRUE, beforeTrs);
2507                             if (!beforeTrsAvail) {
2508                                 break;
2509                             }
2510                             beforeT = beforeTrs.getTime() - 1;
2511                             beforeSav = beforeTrs.getFrom()->getDSTSavings();
2512                             if (beforeSav != 0) {
2513                                 break;
2514                             }
2515                         }
2516 
2517                         // Search for DST rule after the time
2518                         while (TRUE) {
2519                             afterTrsAvail = btz->getNextTransition(afterT, FALSE, afterTrs);
2520                             if (!afterTrsAvail) {
2521                                 break;
2522                             }
2523                             afterT = afterTrs.getTime();
2524                             afterSav = afterTrs.getTo()->getDSTSavings();
2525                             if (afterSav != 0) {
2526                                 break;
2527                             }
2528                         }
2529 
2530                         if (beforeTrsAvail && afterTrsAvail) {
2531                             if (time - beforeT > afterT - time) {
2532                                 resolvedSavings = afterSav;
2533                             } else {
2534                                 resolvedSavings = beforeSav;
2535                             }
2536                         } else if (beforeTrsAvail && beforeSav != 0) {
2537                             resolvedSavings = beforeSav;
2538                         } else if (afterTrsAvail && afterSav != 0) {
2539                             resolvedSavings = afterSav;
2540                         } else {
2541                             resolvedSavings = btz->getDSTSavings();
2542                         }
2543                     } else {
2544                         resolvedSavings = tz.getDSTSavings();
2545                     }
2546                     if (resolvedSavings == 0) {
2547                         // final fallback
2548                         resolvedSavings = U_MILLIS_PER_HOUR;
2549                     }
2550                 }
2551             }
2552             cal.set(UCAL_ZONE_OFFSET, raw);
2553             cal.set(UCAL_DST_OFFSET, resolvedSavings);
2554             delete copy;
2555         }
2556     }
2557 ExitParse:
2558     // Set the parsed result if local calendar is used
2559     // instead of the input calendar
2560     if (U_SUCCESS(status) && workCal != &cal) {
2561         cal.setTimeZone(workCal->getTimeZone());
2562         cal.setTime(workCal->getTime(status), status);
2563     }
2564 
2565     if (numericLeapMonthFormatter != NULL) {
2566         delete numericLeapMonthFormatter;
2567     }
2568     if (calClone != NULL) {
2569         delete calClone;
2570     }
2571 
2572     // If any Calendar calls failed, we pretend that we
2573     // couldn't parse the string, when in reality this isn't quite accurate--
2574     // we did parse it; the Calendar calls just failed.
2575     if (U_FAILURE(status)) {
2576         parsePos.setErrorIndex(pos);
2577         parsePos.setIndex(start);
2578     }
2579 }
2580 
2581 //----------------------------------------------------------------------
2582 
2583 static int32_t
2584 matchStringWithOptionalDot(const UnicodeString &text,
2585                             int32_t index,
2586                             const UnicodeString &data);
2587 
matchQuarterString(const UnicodeString & text,int32_t start,UCalendarDateFields field,const UnicodeString * data,int32_t dataCount,Calendar & cal) const2588 int32_t SimpleDateFormat::matchQuarterString(const UnicodeString& text,
2589                               int32_t start,
2590                               UCalendarDateFields field,
2591                               const UnicodeString* data,
2592                               int32_t dataCount,
2593                               Calendar& cal) const
2594 {
2595     int32_t i = 0;
2596     int32_t count = dataCount;
2597 
2598     // There may be multiple strings in the data[] array which begin with
2599     // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech).
2600     // We keep track of the longest match, and return that.  Note that this
2601     // unfortunately requires us to test all array elements.
2602     int32_t bestMatchLength = 0, bestMatch = -1;
2603     UnicodeString bestMatchName;
2604 
2605     for (; i < count; ++i) {
2606         int32_t matchLength = 0;
2607         if ((matchLength = matchStringWithOptionalDot(text, start, data[i])) > bestMatchLength) {
2608             bestMatchLength = matchLength;
2609             bestMatch = i;
2610         }
2611     }
2612 
2613     if (bestMatch >= 0) {
2614         cal.set(field, bestMatch * 3);
2615         return start + bestMatchLength;
2616     }
2617 
2618     return -start;
2619 }
2620 
matchDayPeriodStrings(const UnicodeString & text,int32_t start,const UnicodeString * data,int32_t dataCount,int32_t & dayPeriod) const2621 int32_t SimpleDateFormat::matchDayPeriodStrings(const UnicodeString& text, int32_t start,
2622                               const UnicodeString* data, int32_t dataCount,
2623                               int32_t &dayPeriod) const
2624 {
2625 
2626     int32_t bestMatchLength = 0, bestMatch = -1;
2627 
2628     for (int32_t i = 0; i < dataCount; ++i) {
2629         int32_t matchLength = 0;
2630         if ((matchLength = matchStringWithOptionalDot(text, start, data[i])) > bestMatchLength) {
2631             bestMatchLength = matchLength;
2632             bestMatch = i;
2633         }
2634     }
2635 
2636     if (bestMatch >= 0) {
2637         dayPeriod = bestMatch;
2638         return start + bestMatchLength;
2639     }
2640 
2641     return -start;
2642 }
2643 
2644 //----------------------------------------------------------------------
matchLiterals(const UnicodeString & pattern,int32_t & patternOffset,const UnicodeString & text,int32_t & textOffset,UBool whitespaceLenient,UBool partialMatchLenient,UBool oldLeniency)2645 UBool SimpleDateFormat::matchLiterals(const UnicodeString &pattern,
2646                                       int32_t &patternOffset,
2647                                       const UnicodeString &text,
2648                                       int32_t &textOffset,
2649                                       UBool whitespaceLenient,
2650                                       UBool partialMatchLenient,
2651                                       UBool oldLeniency)
2652 {
2653     UBool inQuote = FALSE;
2654     UnicodeString literal;
2655     int32_t i = patternOffset;
2656 
2657     // scan pattern looking for contiguous literal characters
2658     for ( ; i < pattern.length(); i += 1) {
2659         UChar ch = pattern.charAt(i);
2660 
2661         if (!inQuote && isSyntaxChar(ch)) {
2662             break;
2663         }
2664 
2665         if (ch == QUOTE) {
2666             // Match a quote literal ('') inside OR outside of quotes
2667             if ((i + 1) < pattern.length() && pattern.charAt(i + 1) == QUOTE) {
2668                 i += 1;
2669             } else {
2670                 inQuote = !inQuote;
2671                 continue;
2672             }
2673         }
2674 
2675         literal += ch;
2676     }
2677 
2678     // at this point, literal contains the literal text
2679     // and i is the index of the next non-literal pattern character.
2680     int32_t p;
2681     int32_t t = textOffset;
2682 
2683     if (whitespaceLenient) {
2684         // trim leading, trailing whitespace from
2685         // the literal text
2686         literal.trim();
2687 
2688         // ignore any leading whitespace in the text
2689         while (t < text.length() && u_isWhitespace(text.charAt(t))) {
2690             t += 1;
2691         }
2692     }
2693 
2694     for (p = 0; p < literal.length() && t < text.length();) {
2695         UBool needWhitespace = FALSE;
2696 
2697         while (p < literal.length() && PatternProps::isWhiteSpace(literal.charAt(p))) {
2698             needWhitespace = TRUE;
2699             p += 1;
2700         }
2701 
2702         if (needWhitespace) {
2703             int32_t tStart = t;
2704 
2705             while (t < text.length()) {
2706                 UChar tch = text.charAt(t);
2707 
2708                 if (!u_isUWhiteSpace(tch) && !PatternProps::isWhiteSpace(tch)) {
2709                     break;
2710                 }
2711 
2712                 t += 1;
2713             }
2714 
2715             // TODO: should we require internal spaces
2716             // in lenient mode? (There won't be any
2717             // leading or trailing spaces)
2718             if (!whitespaceLenient && t == tStart) {
2719                 // didn't find matching whitespace:
2720                 // an error in strict mode
2721                 return FALSE;
2722             }
2723 
2724             // In strict mode, this run of whitespace
2725             // may have been at the end.
2726             if (p >= literal.length()) {
2727                 break;
2728             }
2729         }
2730         if (t >= text.length() || literal.charAt(p) != text.charAt(t)) {
2731             // Ran out of text, or found a non-matching character:
2732             // OK in lenient mode, an error in strict mode.
2733             if (whitespaceLenient) {
2734                 if (t == textOffset && text.charAt(t) == 0x2e &&
2735                         isAfterNonNumericField(pattern, patternOffset)) {
2736                     // Lenient mode and the literal input text begins with a "." and
2737                     // we are after a non-numeric field: We skip the "."
2738                     ++t;
2739                     continue;  // Do not update p.
2740                 }
2741                 // if it is actual whitespace and we're whitespace lenient it's OK
2742 
2743                 UChar wsc = text.charAt(t);
2744                 if(PatternProps::isWhiteSpace(wsc)) {
2745                     // Lenient mode and it's just whitespace we skip it
2746                     ++t;
2747                     continue;  // Do not update p.
2748                 }
2749             }
2750             // hack around oldleniency being a bit of a catch-all bucket and we're just adding support specifically for paritial matches
2751             if(partialMatchLenient && oldLeniency) {
2752                 break;
2753             }
2754 
2755             return FALSE;
2756         }
2757         ++p;
2758         ++t;
2759     }
2760 
2761     // At this point if we're in strict mode we have a complete match.
2762     // If we're in lenient mode we may have a partial match, or no
2763     // match at all.
2764     if (p <= 0) {
2765         // no match. Pretend it matched a run of whitespace
2766         // and ignorables in the text.
2767         const  UnicodeSet *ignorables = NULL;
2768         UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(pattern.charAt(i));
2769         if (patternCharIndex != UDAT_FIELD_COUNT) {
2770             ignorables = SimpleDateFormatStaticSets::getIgnorables(patternCharIndex);
2771         }
2772 
2773         for (t = textOffset; t < text.length(); t += 1) {
2774             UChar ch = text.charAt(t);
2775 
2776             if (ignorables == NULL || !ignorables->contains(ch)) {
2777                 break;
2778             }
2779         }
2780     }
2781 
2782     // if we get here, we've got a complete match.
2783     patternOffset = i - 1;
2784     textOffset = t;
2785 
2786     return TRUE;
2787 }
2788 
2789 //----------------------------------------------------------------------
2790 
matchString(const UnicodeString & text,int32_t start,UCalendarDateFields field,const UnicodeString * data,int32_t dataCount,const UnicodeString * monthPattern,Calendar & cal) const2791 int32_t SimpleDateFormat::matchString(const UnicodeString& text,
2792                               int32_t start,
2793                               UCalendarDateFields field,
2794                               const UnicodeString* data,
2795                               int32_t dataCount,
2796                               const UnicodeString* monthPattern,
2797                               Calendar& cal) const
2798 {
2799     int32_t i = 0;
2800     int32_t count = dataCount;
2801 
2802     if (field == UCAL_DAY_OF_WEEK) i = 1;
2803 
2804     // There may be multiple strings in the data[] array which begin with
2805     // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech).
2806     // We keep track of the longest match, and return that.  Note that this
2807     // unfortunately requires us to test all array elements.
2808     int32_t bestMatchLength = 0, bestMatch = -1;
2809     UnicodeString bestMatchName;
2810     int32_t isLeapMonth = 0;
2811 
2812     for (; i < count; ++i) {
2813         int32_t matchLen = 0;
2814         if ((matchLen = matchStringWithOptionalDot(text, start, data[i])) > bestMatchLength) {
2815             bestMatch = i;
2816             bestMatchLength = matchLen;
2817         }
2818 
2819         if (monthPattern != NULL) {
2820             UErrorCode status = U_ZERO_ERROR;
2821             UnicodeString leapMonthName;
2822             SimpleFormatter(*monthPattern, 1, 1, status).format(data[i], leapMonthName, status);
2823             if (U_SUCCESS(status)) {
2824                 if ((matchLen = matchStringWithOptionalDot(text, start, leapMonthName)) > bestMatchLength) {
2825                     bestMatch = i;
2826                     bestMatchLength = matchLen;
2827                     isLeapMonth = 1;
2828                 }
2829             }
2830         }
2831     }
2832 
2833     if (bestMatch >= 0) {
2834         if (field < UCAL_FIELD_COUNT) {
2835             // Adjustment for Hebrew Calendar month Adar II
2836             if (!strcmp(cal.getType(),"hebrew") && field==UCAL_MONTH && bestMatch==13) {
2837                 cal.set(field,6);
2838             } else {
2839                 if (field == UCAL_YEAR) {
2840                     bestMatch++; // only get here for cyclic year names, which match 1-based years 1-60
2841                 }
2842                 cal.set(field, bestMatch);
2843             }
2844             if (monthPattern != NULL) {
2845                 cal.set(UCAL_IS_LEAP_MONTH, isLeapMonth);
2846             }
2847         }
2848 
2849         return start + bestMatchLength;
2850     }
2851 
2852     return -start;
2853 }
2854 
2855 static int32_t
matchStringWithOptionalDot(const UnicodeString & text,int32_t index,const UnicodeString & data)2856 matchStringWithOptionalDot(const UnicodeString &text,
2857                             int32_t index,
2858                             const UnicodeString &data) {
2859     UErrorCode sts = U_ZERO_ERROR;
2860     int32_t matchLenText = 0;
2861     int32_t matchLenData = 0;
2862 
2863     u_caseInsensitivePrefixMatch(text.getBuffer() + index, text.length() - index,
2864                                  data.getBuffer(), data.length(),
2865                                  0 /* default case option */,
2866                                  &matchLenText, &matchLenData,
2867                                  &sts);
2868     U_ASSERT (U_SUCCESS(sts));
2869 
2870     if (matchLenData == data.length() /* normal match */
2871         || (data.charAt(data.length() - 1) == 0x2e
2872             && matchLenData == data.length() - 1 /* match without trailing dot */)) {
2873         return matchLenText;
2874     }
2875 
2876     return 0;
2877 }
2878 
2879 //----------------------------------------------------------------------
2880 
2881 void
set2DigitYearStart(UDate d,UErrorCode & status)2882 SimpleDateFormat::set2DigitYearStart(UDate d, UErrorCode& status)
2883 {
2884     parseAmbiguousDatesAsAfter(d, status);
2885 }
2886 
2887 /**
2888  * Private member function that converts the parsed date strings into
2889  * timeFields. Returns -start (for ParsePosition) if failed.
2890  */
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) const2891 int32_t SimpleDateFormat::subParse(const UnicodeString& text, int32_t& start, UChar ch, int32_t count,
2892                            UBool obeyCount, UBool allowNegative, UBool ambiguousYear[], int32_t& saveHebrewMonth, Calendar& cal,
2893                            int32_t patLoc, MessageFormat * numericLeapMonthFormatter, UTimeZoneFormatTimeType *tzTimeType,
2894                            int32_t *dayPeriod) const
2895 {
2896     Formattable number;
2897     int32_t value = 0;
2898     int32_t i;
2899     int32_t ps = 0;
2900     UErrorCode status = U_ZERO_ERROR;
2901     ParsePosition pos(0);
2902     UDateFormatField patternCharIndex = DateFormatSymbols::getPatternCharIndex(ch);
2903     const NumberFormat *currentNumberFormat;
2904     UnicodeString temp;
2905     UBool gotNumber = FALSE;
2906 
2907 #if defined (U_DEBUG_CAL)
2908     //fprintf(stderr, "%s:%d - [%c]  st=%d \n", __FILE__, __LINE__, (char) ch, start);
2909 #endif
2910 
2911     if (patternCharIndex == UDAT_FIELD_COUNT) {
2912         return -start;
2913     }
2914 
2915     currentNumberFormat = getNumberFormatByIndex(patternCharIndex);
2916     if (currentNumberFormat == NULL) {
2917         return -start;
2918     }
2919     UCalendarDateFields field = fgPatternIndexToCalendarField[patternCharIndex]; // UCAL_FIELD_COUNT if irrelevant
2920     UnicodeString hebr("hebr", 4, US_INV);
2921 
2922     if (numericLeapMonthFormatter != NULL) {
2923         numericLeapMonthFormatter->setFormats((const Format **)&currentNumberFormat, 1);
2924     }
2925     UBool isChineseCalendar = (uprv_strcmp(cal.getType(),"chinese") == 0 || uprv_strcmp(cal.getType(),"dangi") == 0);
2926 
2927     // If there are any spaces here, skip over them.  If we hit the end
2928     // of the string, then fail.
2929     for (;;) {
2930         if (start >= text.length()) {
2931             return -start;
2932         }
2933         UChar32 c = text.char32At(start);
2934         if (!u_isUWhiteSpace(c) /*||*/ && !PatternProps::isWhiteSpace(c)) {
2935             break;
2936         }
2937         start += U16_LENGTH(c);
2938     }
2939     pos.setIndex(start);
2940 
2941     // We handle a few special cases here where we need to parse
2942     // a number value.  We handle further, more generic cases below.  We need
2943     // to handle some of them here because some fields require extra processing on
2944     // the parsed value.
2945     if (patternCharIndex == UDAT_HOUR_OF_DAY1_FIELD ||                       // k
2946         patternCharIndex == UDAT_HOUR_OF_DAY0_FIELD ||                       // H
2947         patternCharIndex == UDAT_HOUR1_FIELD ||                              // h
2948         patternCharIndex == UDAT_HOUR0_FIELD ||                              // K
2949         (patternCharIndex == UDAT_DOW_LOCAL_FIELD && count <= 2) ||          // e
2950         (patternCharIndex == UDAT_STANDALONE_DAY_FIELD && count <= 2) ||     // c
2951         (patternCharIndex == UDAT_MONTH_FIELD && count <= 2) ||              // M
2952         (patternCharIndex == UDAT_STANDALONE_MONTH_FIELD && count <= 2) ||   // L
2953         (patternCharIndex == UDAT_QUARTER_FIELD && count <= 2) ||            // Q
2954         (patternCharIndex == UDAT_STANDALONE_QUARTER_FIELD && count <= 2) || // q
2955         patternCharIndex == UDAT_YEAR_FIELD ||                               // y
2956         patternCharIndex == UDAT_YEAR_WOY_FIELD ||                           // Y
2957         patternCharIndex == UDAT_YEAR_NAME_FIELD ||                          // U (falls back to numeric)
2958         (patternCharIndex == UDAT_ERA_FIELD && isChineseCalendar) ||         // G
2959         patternCharIndex == UDAT_FRACTIONAL_SECOND_FIELD)                    // S
2960     {
2961         int32_t parseStart = pos.getIndex();
2962         // It would be good to unify this with the obeyCount logic below,
2963         // but that's going to be difficult.
2964         const UnicodeString* src;
2965 
2966         UBool parsedNumericLeapMonth = FALSE;
2967         if (numericLeapMonthFormatter != NULL && (patternCharIndex == UDAT_MONTH_FIELD || patternCharIndex == UDAT_STANDALONE_MONTH_FIELD)) {
2968             int32_t argCount;
2969             Formattable * args = numericLeapMonthFormatter->parse(text, pos, argCount);
2970             if (args != NULL && argCount == 1 && pos.getIndex() > parseStart && args[0].isNumeric()) {
2971                 parsedNumericLeapMonth = TRUE;
2972                 number.setLong(args[0].getLong());
2973                 cal.set(UCAL_IS_LEAP_MONTH, 1);
2974                 delete[] args;
2975             } else {
2976                 pos.setIndex(parseStart);
2977                 cal.set(UCAL_IS_LEAP_MONTH, 0);
2978             }
2979         }
2980 
2981         if (!parsedNumericLeapMonth) {
2982             if (obeyCount) {
2983                 if ((start+count) > text.length()) {
2984                     return -start;
2985                 }
2986 
2987                 text.extractBetween(0, start + count, temp);
2988                 src = &temp;
2989             } else {
2990                 src = &text;
2991             }
2992 
2993             parseInt(*src, number, pos, allowNegative,currentNumberFormat);
2994         }
2995 
2996         int32_t txtLoc = pos.getIndex();
2997 
2998         if (txtLoc > parseStart) {
2999             value = number.getLong();
3000             gotNumber = TRUE;
3001 
3002             // suffix processing
3003             if (value < 0 ) {
3004                 txtLoc = checkIntSuffix(text, txtLoc, patLoc+1, TRUE);
3005                 if (txtLoc != pos.getIndex()) {
3006                     value *= -1;
3007                 }
3008             }
3009             else {
3010                 txtLoc = checkIntSuffix(text, txtLoc, patLoc+1, FALSE);
3011             }
3012 
3013             if (!getBooleanAttribute(UDAT_PARSE_ALLOW_WHITESPACE, status)) {
3014                 // Check the range of the value
3015                 int32_t bias = gFieldRangeBias[patternCharIndex];
3016                 if (bias >= 0 && (value > cal.getMaximum(field) + bias || value < cal.getMinimum(field) + bias)) {
3017                     return -start;
3018                 }
3019             }
3020 
3021             pos.setIndex(txtLoc);
3022         }
3023     }
3024 
3025     // Make sure that we got a number if
3026     // we want one, and didn't get one
3027     // if we don't want one.
3028     switch (patternCharIndex) {
3029         case UDAT_HOUR_OF_DAY1_FIELD:
3030         case UDAT_HOUR_OF_DAY0_FIELD:
3031         case UDAT_HOUR1_FIELD:
3032         case UDAT_HOUR0_FIELD:
3033             // special range check for hours:
3034             if (value < 0 || value > 24) {
3035                 return -start;
3036             }
3037 
3038             // fall through to gotNumber check
3039             U_FALLTHROUGH;
3040         case UDAT_YEAR_FIELD:
3041         case UDAT_YEAR_WOY_FIELD:
3042         case UDAT_FRACTIONAL_SECOND_FIELD:
3043             // these must be a number
3044             if (! gotNumber) {
3045                 return -start;
3046             }
3047 
3048             break;
3049 
3050         default:
3051             // we check the rest of the fields below.
3052             break;
3053     }
3054 
3055     switch (patternCharIndex) {
3056     case UDAT_ERA_FIELD:
3057         if (isChineseCalendar) {
3058             if (!gotNumber) {
3059                 return -start;
3060             }
3061             cal.set(UCAL_ERA, value);
3062             return pos.getIndex();
3063         }
3064         if (count == 5) {
3065             ps = matchString(text, start, UCAL_ERA, fSymbols->fNarrowEras, fSymbols->fNarrowErasCount, NULL, cal);
3066         } else if (count == 4) {
3067             ps = matchString(text, start, UCAL_ERA, fSymbols->fEraNames, fSymbols->fEraNamesCount, NULL, cal);
3068         } else {
3069             ps = matchString(text, start, UCAL_ERA, fSymbols->fEras, fSymbols->fErasCount, NULL, cal);
3070         }
3071 
3072         // check return position, if it equals -start, then matchString error
3073         // special case the return code so we don't necessarily fail out until we
3074         // verify no year information also
3075         if (ps == -start)
3076             ps--;
3077 
3078         return ps;
3079 
3080     case UDAT_YEAR_FIELD:
3081         // If there are 3 or more YEAR pattern characters, this indicates
3082         // that the year value is to be treated literally, without any
3083         // two-digit year adjustments (e.g., from "01" to 2001).  Otherwise
3084         // we made adjustments to place the 2-digit year in the proper
3085         // century, for parsed strings from "00" to "99".  Any other string
3086         // is treated literally:  "2250", "-1", "1", "002".
3087         if (fDateOverride.compare(hebr)==0 && value < 1000) {
3088             value += HEBREW_CAL_CUR_MILLENIUM_START_YEAR;
3089         } else if (text.moveIndex32(start, 2) == pos.getIndex() && !isChineseCalendar
3090             && u_isdigit(text.char32At(start))
3091             && u_isdigit(text.char32At(text.moveIndex32(start, 1))))
3092         {
3093             // only adjust year for patterns less than 3.
3094             if(count < 3) {
3095                 // Assume for example that the defaultCenturyStart is 6/18/1903.
3096                 // This means that two-digit years will be forced into the range
3097                 // 6/18/1903 to 6/17/2003.  As a result, years 00, 01, and 02
3098                 // correspond to 2000, 2001, and 2002.  Years 04, 05, etc. correspond
3099                 // to 1904, 1905, etc.  If the year is 03, then it is 2003 if the
3100                 // other fields specify a date before 6/18, or 1903 if they specify a
3101                 // date afterwards.  As a result, 03 is an ambiguous year.  All other
3102                 // two-digit years are unambiguous.
3103                 if(fHaveDefaultCentury) { // check if this formatter even has a pivot year
3104                     int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100;
3105                     ambiguousYear[0] = (value == ambiguousTwoDigitYear);
3106                     value += (fDefaultCenturyStartYear/100)*100 +
3107                             (value < ambiguousTwoDigitYear ? 100 : 0);
3108                 }
3109             }
3110         }
3111         cal.set(UCAL_YEAR, value);
3112 
3113         // Delayed checking for adjustment of Hebrew month numbers in non-leap years.
3114         if (saveHebrewMonth >= 0) {
3115             HebrewCalendar *hc = (HebrewCalendar*)&cal;
3116             if (!hc->isLeapYear(value) && saveHebrewMonth >= 6) {
3117                cal.set(UCAL_MONTH,saveHebrewMonth);
3118             } else {
3119                cal.set(UCAL_MONTH,saveHebrewMonth-1);
3120             }
3121             saveHebrewMonth = -1;
3122         }
3123         return pos.getIndex();
3124 
3125     case UDAT_YEAR_WOY_FIELD:
3126         // Comment is the same as for UDAT_Year_FIELDs - look above
3127         if (fDateOverride.compare(hebr)==0 && value < 1000) {
3128             value += HEBREW_CAL_CUR_MILLENIUM_START_YEAR;
3129         } else if (text.moveIndex32(start, 2) == pos.getIndex()
3130             && u_isdigit(text.char32At(start))
3131             && u_isdigit(text.char32At(text.moveIndex32(start, 1)))
3132             && fHaveDefaultCentury )
3133         {
3134             int32_t ambiguousTwoDigitYear = fDefaultCenturyStartYear % 100;
3135             ambiguousYear[0] = (value == ambiguousTwoDigitYear);
3136             value += (fDefaultCenturyStartYear/100)*100 +
3137                 (value < ambiguousTwoDigitYear ? 100 : 0);
3138         }
3139         cal.set(UCAL_YEAR_WOY, value);
3140         return pos.getIndex();
3141 
3142     case UDAT_YEAR_NAME_FIELD:
3143         if (fSymbols->fShortYearNames != NULL) {
3144             int32_t newStart = matchString(text, start, UCAL_YEAR, fSymbols->fShortYearNames, fSymbols->fShortYearNamesCount, NULL, cal);
3145             if (newStart > 0) {
3146                 return newStart;
3147             }
3148         }
3149         if (gotNumber && (getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC,status) || value > fSymbols->fShortYearNamesCount)) {
3150             cal.set(UCAL_YEAR, value);
3151             return pos.getIndex();
3152         }
3153         return -start;
3154 
3155     case UDAT_MONTH_FIELD:
3156     case UDAT_STANDALONE_MONTH_FIELD:
3157         if (gotNumber) // i.e., M or MM.
3158         {
3159             // When parsing month numbers from the Hebrew Calendar, we might need to adjust the month depending on whether
3160             // 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
3161             // the year is parsed.
3162             if (!strcmp(cal.getType(),"hebrew")) {
3163                 HebrewCalendar *hc = (HebrewCalendar*)&cal;
3164                 if (cal.isSet(UCAL_YEAR)) {
3165                    UErrorCode monthStatus = U_ZERO_ERROR;
3166                    if (!hc->isLeapYear(hc->get(UCAL_YEAR, monthStatus)) && value >= 6) {
3167                        cal.set(UCAL_MONTH, value);
3168                    } else {
3169                        cal.set(UCAL_MONTH, value - 1);
3170                    }
3171                 } else {
3172                     saveHebrewMonth = value;
3173                 }
3174             } else {
3175                 // Don't want to parse the month if it is a string
3176                 // while pattern uses numeric style: M/MM, L/LL
3177                 // [We computed 'value' above.]
3178                 cal.set(UCAL_MONTH, value - 1);
3179             }
3180             return pos.getIndex();
3181         } else {
3182             // count >= 3 // i.e., MMM/MMMM, LLL/LLLL
3183             // Want to be able to parse both short and long forms.
3184             // Try count == 4 first:
3185             UnicodeString * wideMonthPat = NULL;
3186             UnicodeString * shortMonthPat = NULL;
3187             if (fSymbols->fLeapMonthPatterns != NULL && fSymbols->fLeapMonthPatternsCount >= DateFormatSymbols::kMonthPatternsCount) {
3188                 if (patternCharIndex==UDAT_MONTH_FIELD) {
3189                     wideMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatWide];
3190                     shortMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternFormatAbbrev];
3191                 } else {
3192                     wideMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneWide];
3193                     shortMonthPat = &fSymbols->fLeapMonthPatterns[DateFormatSymbols::kLeapMonthPatternStandaloneAbbrev];
3194                 }
3195             }
3196             int32_t newStart = 0;
3197             if (patternCharIndex==UDAT_MONTH_FIELD) {
3198                 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
3199                     newStart = matchString(text, start, UCAL_MONTH, fSymbols->fMonths, fSymbols->fMonthsCount, wideMonthPat, cal); // try MMMM
3200                     if (newStart > 0) {
3201                         return newStart;
3202                     }
3203                 }
3204                 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
3205                     newStart = matchString(text, start, UCAL_MONTH, fSymbols->fShortMonths, fSymbols->fShortMonthsCount, shortMonthPat, cal); // try MMM
3206                 }
3207             } else {
3208                 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
3209                     newStart = matchString(text, start, UCAL_MONTH, fSymbols->fStandaloneMonths, fSymbols->fStandaloneMonthsCount, wideMonthPat, cal); // try LLLL
3210                     if (newStart > 0) {
3211                         return newStart;
3212                     }
3213                 }
3214                 if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
3215                     newStart = matchString(text, start, UCAL_MONTH, fSymbols->fStandaloneShortMonths, fSymbols->fStandaloneShortMonthsCount, shortMonthPat, cal); // try LLL
3216                 }
3217             }
3218             if (newStart > 0 || !getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status))  // currently we do not try to parse MMMMM/LLLLL: #8860
3219                 return newStart;
3220             // else we allowing parsing as number, below
3221         }
3222         break;
3223 
3224     case UDAT_HOUR_OF_DAY1_FIELD:
3225         // [We computed 'value' above.]
3226         if (value == cal.getMaximum(UCAL_HOUR_OF_DAY) + 1)
3227             value = 0;
3228 
3229         // fall through to set field
3230         U_FALLTHROUGH;
3231     case UDAT_HOUR_OF_DAY0_FIELD:
3232         cal.set(UCAL_HOUR_OF_DAY, value);
3233         return pos.getIndex();
3234 
3235     case UDAT_FRACTIONAL_SECOND_FIELD:
3236         // Fractional seconds left-justify
3237         i = countDigits(text, start, pos.getIndex());
3238         if (i < 3) {
3239             while (i < 3) {
3240                 value *= 10;
3241                 i++;
3242             }
3243         } else {
3244             int32_t a = 1;
3245             while (i > 3) {
3246                 a *= 10;
3247                 i--;
3248             }
3249             value /= a;
3250         }
3251         cal.set(UCAL_MILLISECOND, value);
3252         return pos.getIndex();
3253 
3254     case UDAT_DOW_LOCAL_FIELD:
3255         if (gotNumber) // i.e., e or ee
3256         {
3257             // [We computed 'value' above.]
3258             cal.set(UCAL_DOW_LOCAL, value);
3259             return pos.getIndex();
3260         }
3261         // else for eee-eeeee fall through to handling of EEE-EEEEE
3262         // fall through, do not break here
3263         U_FALLTHROUGH;
3264     case UDAT_DAY_OF_WEEK_FIELD:
3265         {
3266             // Want to be able to parse both short and long forms.
3267             // Try count == 4 (EEEE) wide first:
3268             int32_t newStart = 0;
3269             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
3270                 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
3271                                           fSymbols->fWeekdays, fSymbols->fWeekdaysCount, NULL, cal)) > 0)
3272                     return newStart;
3273             }
3274             // EEEE wide failed, now try EEE abbreviated
3275             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
3276                 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
3277                                        fSymbols->fShortWeekdays, fSymbols->fShortWeekdaysCount, NULL, cal)) > 0)
3278                     return newStart;
3279             }
3280             // EEE abbreviated failed, now try EEEEEE short
3281             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 6) {
3282                 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
3283                                        fSymbols->fShorterWeekdays, fSymbols->fShorterWeekdaysCount, NULL, cal)) > 0)
3284                     return newStart;
3285             }
3286             // EEEEEE short failed, now try EEEEE narrow
3287             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 5) {
3288                 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
3289                                        fSymbols->fNarrowWeekdays, fSymbols->fNarrowWeekdaysCount, NULL, cal)) > 0)
3290                     return newStart;
3291             }
3292             if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status) || patternCharIndex == UDAT_DAY_OF_WEEK_FIELD)
3293                 return newStart;
3294             // else we allowing parsing as number, below
3295         }
3296         break;
3297 
3298     case UDAT_STANDALONE_DAY_FIELD:
3299         {
3300             if (gotNumber) // c or cc
3301             {
3302                 // [We computed 'value' above.]
3303                 cal.set(UCAL_DOW_LOCAL, value);
3304                 return pos.getIndex();
3305             }
3306             // Want to be able to parse both short and long forms.
3307             // Try count == 4 (cccc) first:
3308             int32_t newStart = 0;
3309             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
3310                 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
3311                                       fSymbols->fStandaloneWeekdays, fSymbols->fStandaloneWeekdaysCount, NULL, cal)) > 0)
3312                     return newStart;
3313             }
3314             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
3315                 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
3316                                           fSymbols->fStandaloneShortWeekdays, fSymbols->fStandaloneShortWeekdaysCount, NULL, cal)) > 0)
3317                     return newStart;
3318             }
3319             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 6) {
3320                 if ((newStart = matchString(text, start, UCAL_DAY_OF_WEEK,
3321                                           fSymbols->fStandaloneShorterWeekdays, fSymbols->fStandaloneShorterWeekdaysCount, NULL, cal)) > 0)
3322                     return newStart;
3323             }
3324             if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status))
3325                 return newStart;
3326             // else we allowing parsing as number, below
3327         }
3328         break;
3329 
3330     case UDAT_AM_PM_FIELD:
3331         {
3332             // optionally try both wide/abbrev and narrow forms
3333             int32_t newStart = 0;
3334             // try wide/abbrev
3335             if( getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count < 5 ) {
3336                 if ((newStart = matchString(text, start, UCAL_AM_PM, fSymbols->fAmPms, fSymbols->fAmPmsCount, NULL, cal)) > 0) {
3337                     return newStart;
3338                 }
3339             }
3340             // try narrow
3341             if( getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count >= 5 ) {
3342                 if ((newStart = matchString(text, start, UCAL_AM_PM, fSymbols->fNarrowAmPms, fSymbols->fNarrowAmPmsCount, NULL, cal)) > 0) {
3343                     return newStart;
3344                 }
3345             }
3346             // no matches for given options
3347             return -start;
3348         }
3349 
3350     case UDAT_HOUR1_FIELD:
3351         // [We computed 'value' above.]
3352         if (value == cal.getLeastMaximum(UCAL_HOUR)+1)
3353             value = 0;
3354 
3355         // fall through to set field
3356         U_FALLTHROUGH;
3357     case UDAT_HOUR0_FIELD:
3358         cal.set(UCAL_HOUR, value);
3359         return pos.getIndex();
3360 
3361     case UDAT_QUARTER_FIELD:
3362         if (gotNumber) // i.e., Q or QQ.
3363         {
3364             // Don't want to parse the month if it is a string
3365             // while pattern uses numeric style: Q or QQ.
3366             // [We computed 'value' above.]
3367             cal.set(UCAL_MONTH, (value - 1) * 3);
3368             return pos.getIndex();
3369         } else {
3370             // count >= 3 // i.e., QQQ or QQQQ
3371             // Want to be able to parse both short and long forms.
3372             // Try count == 4 first:
3373             int32_t newStart = 0;
3374 
3375             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
3376                 if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
3377                                       fSymbols->fQuarters, fSymbols->fQuartersCount, cal)) > 0)
3378                     return newStart;
3379             }
3380             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
3381                 if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
3382                                           fSymbols->fShortQuarters, fSymbols->fShortQuartersCount, cal)) > 0)
3383                     return newStart;
3384             }
3385             if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status))
3386                 return newStart;
3387             // else we allowing parsing as number, below
3388             if(!getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status))
3389                 return -start;
3390         }
3391         break;
3392 
3393     case UDAT_STANDALONE_QUARTER_FIELD:
3394         if (gotNumber) // i.e., q or qq.
3395         {
3396             // Don't want to parse the month if it is a string
3397             // while pattern uses numeric style: q or q.
3398             // [We computed 'value' above.]
3399             cal.set(UCAL_MONTH, (value - 1) * 3);
3400             return pos.getIndex();
3401         } else {
3402             // count >= 3 // i.e., qqq or qqqq
3403             // Want to be able to parse both short and long forms.
3404             // Try count == 4 first:
3405             int32_t newStart = 0;
3406 
3407             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
3408                 if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
3409                                       fSymbols->fStandaloneQuarters, fSymbols->fStandaloneQuartersCount, cal)) > 0)
3410                     return newStart;
3411             }
3412             if(getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
3413                 if ((newStart = matchQuarterString(text, start, UCAL_MONTH,
3414                                           fSymbols->fStandaloneShortQuarters, fSymbols->fStandaloneShortQuartersCount, cal)) > 0)
3415                     return newStart;
3416             }
3417             if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status))
3418                 return newStart;
3419             // else we allowing parsing as number, below
3420             if(!getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status))
3421                 return -start;
3422         }
3423         break;
3424 
3425     case UDAT_TIMEZONE_FIELD: // 'z'
3426         {
3427             UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_SPECIFIC_SHORT : UTZFMT_STYLE_SPECIFIC_LONG;
3428             const TimeZoneFormat *tzfmt = tzFormat(status);
3429             if (U_SUCCESS(status)) {
3430                 TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
3431                 if (tz != NULL) {
3432                     cal.adoptTimeZone(tz);
3433                     return pos.getIndex();
3434                 }
3435             }
3436             return -start;
3437     }
3438         break;
3439     case UDAT_TIMEZONE_RFC_FIELD: // 'Z'
3440         {
3441             UTimeZoneFormatStyle style = (count < 4) ?
3442                 UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL : ((count == 5) ? UTZFMT_STYLE_ISO_EXTENDED_FULL: UTZFMT_STYLE_LOCALIZED_GMT);
3443             const TimeZoneFormat *tzfmt = tzFormat(status);
3444             if (U_SUCCESS(status)) {
3445                 TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
3446                 if (tz != NULL) {
3447                     cal.adoptTimeZone(tz);
3448                     return pos.getIndex();
3449                 }
3450             }
3451             return -start;
3452         }
3453     case UDAT_TIMEZONE_GENERIC_FIELD: // 'v'
3454         {
3455             UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_GENERIC_SHORT : UTZFMT_STYLE_GENERIC_LONG;
3456             const TimeZoneFormat *tzfmt = tzFormat(status);
3457             if (U_SUCCESS(status)) {
3458                 TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
3459                 if (tz != NULL) {
3460                     cal.adoptTimeZone(tz);
3461                     return pos.getIndex();
3462                 }
3463             }
3464             return -start;
3465         }
3466     case UDAT_TIMEZONE_SPECIAL_FIELD: // 'V'
3467         {
3468             UTimeZoneFormatStyle style;
3469             switch (count) {
3470             case 1:
3471                 style = UTZFMT_STYLE_ZONE_ID_SHORT;
3472                 break;
3473             case 2:
3474                 style = UTZFMT_STYLE_ZONE_ID;
3475                 break;
3476             case 3:
3477                 style = UTZFMT_STYLE_EXEMPLAR_LOCATION;
3478                 break;
3479             default:
3480                 style = UTZFMT_STYLE_GENERIC_LOCATION;
3481                 break;
3482             }
3483             const TimeZoneFormat *tzfmt = tzFormat(status);
3484             if (U_SUCCESS(status)) {
3485                 TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
3486                 if (tz != NULL) {
3487                     cal.adoptTimeZone(tz);
3488                     return pos.getIndex();
3489                 }
3490             }
3491             return -start;
3492         }
3493     case UDAT_TIMEZONE_LOCALIZED_GMT_OFFSET_FIELD: // 'O'
3494         {
3495             UTimeZoneFormatStyle style = (count < 4) ? UTZFMT_STYLE_LOCALIZED_GMT_SHORT : UTZFMT_STYLE_LOCALIZED_GMT;
3496             const TimeZoneFormat *tzfmt = tzFormat(status);
3497             if (U_SUCCESS(status)) {
3498                 TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
3499                 if (tz != NULL) {
3500                     cal.adoptTimeZone(tz);
3501                     return pos.getIndex();
3502                 }
3503             }
3504             return -start;
3505         }
3506     case UDAT_TIMEZONE_ISO_FIELD: // 'X'
3507         {
3508             UTimeZoneFormatStyle style;
3509             switch (count) {
3510             case 1:
3511                 style = UTZFMT_STYLE_ISO_BASIC_SHORT;
3512                 break;
3513             case 2:
3514                 style = UTZFMT_STYLE_ISO_BASIC_FIXED;
3515                 break;
3516             case 3:
3517                 style = UTZFMT_STYLE_ISO_EXTENDED_FIXED;
3518                 break;
3519             case 4:
3520                 style = UTZFMT_STYLE_ISO_BASIC_FULL;
3521                 break;
3522             default:
3523                 style = UTZFMT_STYLE_ISO_EXTENDED_FULL;
3524                 break;
3525             }
3526             const TimeZoneFormat *tzfmt = tzFormat(status);
3527             if (U_SUCCESS(status)) {
3528                 TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
3529                 if (tz != NULL) {
3530                     cal.adoptTimeZone(tz);
3531                     return pos.getIndex();
3532                 }
3533             }
3534             return -start;
3535         }
3536     case UDAT_TIMEZONE_ISO_LOCAL_FIELD: // 'x'
3537         {
3538             UTimeZoneFormatStyle style;
3539             switch (count) {
3540             case 1:
3541                 style = UTZFMT_STYLE_ISO_BASIC_LOCAL_SHORT;
3542                 break;
3543             case 2:
3544                 style = UTZFMT_STYLE_ISO_BASIC_LOCAL_FIXED;
3545                 break;
3546             case 3:
3547                 style = UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FIXED;
3548                 break;
3549             case 4:
3550                 style = UTZFMT_STYLE_ISO_BASIC_LOCAL_FULL;
3551                 break;
3552             default:
3553                 style = UTZFMT_STYLE_ISO_EXTENDED_LOCAL_FULL;
3554                 break;
3555             }
3556             const TimeZoneFormat *tzfmt = tzFormat(status);
3557             if (U_SUCCESS(status)) {
3558                 TimeZone *tz = tzfmt->parse(style, text, pos, tzTimeType);
3559                 if (tz != NULL) {
3560                     cal.adoptTimeZone(tz);
3561                     return pos.getIndex();
3562                 }
3563             }
3564             return -start;
3565         }
3566     // currently no pattern character is defined for UDAT_TIME_SEPARATOR_FIELD
3567     // so we should not get here. Leave support in for future definition.
3568     case UDAT_TIME_SEPARATOR_FIELD:
3569         {
3570             static const UChar def_sep = DateFormatSymbols::DEFAULT_TIME_SEPARATOR;
3571             static const UChar alt_sep = DateFormatSymbols::ALTERNATE_TIME_SEPARATOR;
3572 
3573             // Try matching a time separator.
3574             int32_t count_sep = 1;
3575             UnicodeString data[3];
3576             fSymbols->getTimeSeparatorString(data[0]);
3577 
3578             // Add the default, if different from the locale.
3579             if (data[0].compare(&def_sep, 1) != 0) {
3580                 data[count_sep++].setTo(def_sep);
3581             }
3582 
3583             // If lenient, add also the alternate, if different from the locale.
3584             if (isLenient() && data[0].compare(&alt_sep, 1) != 0) {
3585                 data[count_sep++].setTo(alt_sep);
3586             }
3587 
3588             return matchString(text, start, UCAL_FIELD_COUNT /* => nothing to set */, data, count_sep, NULL, cal);
3589         }
3590 
3591     case UDAT_AM_PM_MIDNIGHT_NOON_FIELD:
3592     {
3593         U_ASSERT(dayPeriod != NULL);
3594         int32_t ampmStart = subParse(text, start, 0x61, count,
3595                            obeyCount, allowNegative, ambiguousYear, saveHebrewMonth, cal,
3596                            patLoc, numericLeapMonthFormatter, tzTimeType);
3597 
3598         if (ampmStart > 0) {
3599             return ampmStart;
3600         } else {
3601             int32_t newStart = 0;
3602 
3603             // Only match the first two strings from the day period strings array.
3604             if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
3605                 if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fAbbreviatedDayPeriods,
3606                                                         2, *dayPeriod)) > 0) {
3607                     return newStart;
3608                 }
3609             }
3610             if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 5) {
3611                 if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fNarrowDayPeriods,
3612                                                         2, *dayPeriod)) > 0) {
3613                     return newStart;
3614                 }
3615             }
3616             // count == 4, but allow other counts
3617             if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status)) {
3618                 if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fWideDayPeriods,
3619                                                         2, *dayPeriod)) > 0) {
3620                     return newStart;
3621                 }
3622             }
3623 
3624             return -start;
3625         }
3626     }
3627 
3628     case UDAT_FLEXIBLE_DAY_PERIOD_FIELD:
3629     {
3630         U_ASSERT(dayPeriod != NULL);
3631         int32_t newStart = 0;
3632 
3633         if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 3) {
3634             if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fAbbreviatedDayPeriods,
3635                                 fSymbols->fAbbreviatedDayPeriodsCount, *dayPeriod)) > 0) {
3636                 return newStart;
3637             }
3638         }
3639         if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 5) {
3640             if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fNarrowDayPeriods,
3641                                 fSymbols->fNarrowDayPeriodsCount, *dayPeriod)) > 0) {
3642                 return newStart;
3643             }
3644         }
3645         if (getBooleanAttribute(UDAT_PARSE_MULTIPLE_PATTERNS_FOR_MATCH, status) || count == 4) {
3646             if ((newStart = matchDayPeriodStrings(text, start, fSymbols->fWideDayPeriods,
3647                                 fSymbols->fWideDayPeriodsCount, *dayPeriod)) > 0) {
3648                 return newStart;
3649             }
3650         }
3651 
3652         return -start;
3653     }
3654 
3655     default:
3656         // Handle "generic" fields
3657         // this is now handled below, outside the switch block
3658         break;
3659     }
3660     // Handle "generic" fields:
3661     // switch default case now handled here (outside switch block) to allow
3662     // parsing of some string fields as digits for lenient case
3663 
3664     int32_t parseStart = pos.getIndex();
3665     const UnicodeString* src;
3666     if (obeyCount) {
3667         if ((start+count) > text.length()) {
3668             return -start;
3669         }
3670         text.extractBetween(0, start + count, temp);
3671         src = &temp;
3672     } else {
3673         src = &text;
3674     }
3675     parseInt(*src, number, pos, allowNegative,currentNumberFormat);
3676     if (pos.getIndex() != parseStart) {
3677         int32_t val = number.getLong();
3678 
3679         // Don't need suffix processing here (as in number processing at the beginning of the function);
3680         // the new fields being handled as numeric values (month, weekdays, quarters) should not have suffixes.
3681 
3682         if (!getBooleanAttribute(UDAT_PARSE_ALLOW_NUMERIC, status)) {
3683             // Check the range of the value
3684             int32_t bias = gFieldRangeBias[patternCharIndex];
3685             if (bias >= 0 && (val > cal.getMaximum(field) + bias || val < cal.getMinimum(field) + bias)) {
3686                 return -start;
3687             }
3688         }
3689 
3690         // For the following, need to repeat some of the "if (gotNumber)" code above:
3691         // UDAT_[STANDALONE_]MONTH_FIELD, UDAT_DOW_LOCAL_FIELD, UDAT_STANDALONE_DAY_FIELD,
3692         // UDAT_[STANDALONE_]QUARTER_FIELD
3693         switch (patternCharIndex) {
3694         case UDAT_MONTH_FIELD:
3695             // See notes under UDAT_MONTH_FIELD case above
3696             if (!strcmp(cal.getType(),"hebrew")) {
3697                 HebrewCalendar *hc = (HebrewCalendar*)&cal;
3698                 if (cal.isSet(UCAL_YEAR)) {
3699                    UErrorCode monthStatus = U_ZERO_ERROR;
3700                    if (!hc->isLeapYear(hc->get(UCAL_YEAR, monthStatus)) && val >= 6) {
3701                        cal.set(UCAL_MONTH, val);
3702                    } else {
3703                        cal.set(UCAL_MONTH, val - 1);
3704                    }
3705                 } else {
3706                     saveHebrewMonth = val;
3707                 }
3708             } else {
3709                 cal.set(UCAL_MONTH, val - 1);
3710             }
3711             break;
3712         case UDAT_STANDALONE_MONTH_FIELD:
3713             cal.set(UCAL_MONTH, val - 1);
3714             break;
3715         case UDAT_DOW_LOCAL_FIELD:
3716         case UDAT_STANDALONE_DAY_FIELD:
3717             cal.set(UCAL_DOW_LOCAL, val);
3718             break;
3719         case UDAT_QUARTER_FIELD:
3720         case UDAT_STANDALONE_QUARTER_FIELD:
3721              cal.set(UCAL_MONTH, (val - 1) * 3);
3722              break;
3723         case UDAT_RELATED_YEAR_FIELD:
3724             cal.setRelatedYear(val);
3725             break;
3726         default:
3727             cal.set(field, val);
3728             break;
3729         }
3730         return pos.getIndex();
3731     }
3732     return -start;
3733 }
3734 
3735 /**
3736  * Parse an integer using fNumberFormat.  This method is semantically
3737  * const, but actually may modify fNumberFormat.
3738  */
parseInt(const UnicodeString & text,Formattable & number,ParsePosition & pos,UBool allowNegative,const NumberFormat * fmt) const3739 void SimpleDateFormat::parseInt(const UnicodeString& text,
3740                                 Formattable& number,
3741                                 ParsePosition& pos,
3742                                 UBool allowNegative,
3743                                 const NumberFormat *fmt) const {
3744     parseInt(text, number, -1, pos, allowNegative,fmt);
3745 }
3746 
3747 /**
3748  * Parse an integer using fNumberFormat up to maxDigits.
3749  */
parseInt(const UnicodeString & text,Formattable & number,int32_t maxDigits,ParsePosition & pos,UBool allowNegative,const NumberFormat * fmt) const3750 void SimpleDateFormat::parseInt(const UnicodeString& text,
3751                                 Formattable& number,
3752                                 int32_t maxDigits,
3753                                 ParsePosition& pos,
3754                                 UBool allowNegative,
3755                                 const NumberFormat *fmt) const {
3756     UnicodeString oldPrefix;
3757     auto* fmtAsDF = dynamic_cast<const DecimalFormat*>(fmt);
3758     LocalPointer<DecimalFormat> df;
3759     if (!allowNegative && fmtAsDF != nullptr) {
3760         df.adoptInstead(dynamic_cast<DecimalFormat*>(fmtAsDF->clone()));
3761         if (df.isNull()) {
3762             // Memory allocation error
3763             return;
3764         }
3765         df->setNegativePrefix(UnicodeString(TRUE, SUPPRESS_NEGATIVE_PREFIX, -1));
3766         fmt = df.getAlias();
3767     }
3768     int32_t oldPos = pos.getIndex();
3769     fmt->parse(text, number, pos);
3770 
3771     if (maxDigits > 0) {
3772         // adjust the result to fit into
3773         // the maxDigits and move the position back
3774         int32_t nDigits = pos.getIndex() - oldPos;
3775         if (nDigits > maxDigits) {
3776             int32_t val = number.getLong();
3777             nDigits -= maxDigits;
3778             while (nDigits > 0) {
3779                 val /= 10;
3780                 nDigits--;
3781             }
3782             pos.setIndex(oldPos + maxDigits);
3783             number.setLong(val);
3784         }
3785     }
3786 }
3787 
countDigits(const UnicodeString & text,int32_t start,int32_t end) const3788 int32_t SimpleDateFormat::countDigits(const UnicodeString& text, int32_t start, int32_t end) const {
3789     int32_t numDigits = 0;
3790     int32_t idx = start;
3791     while (idx < end) {
3792         UChar32 cp = text.char32At(idx);
3793         if (u_isdigit(cp)) {
3794             numDigits++;
3795         }
3796         idx += U16_LENGTH(cp);
3797     }
3798     return numDigits;
3799 }
3800 
3801 //----------------------------------------------------------------------
3802 
translatePattern(const UnicodeString & originalPattern,UnicodeString & translatedPattern,const UnicodeString & from,const UnicodeString & to,UErrorCode & status)3803 void SimpleDateFormat::translatePattern(const UnicodeString& originalPattern,
3804                                         UnicodeString& translatedPattern,
3805                                         const UnicodeString& from,
3806                                         const UnicodeString& to,
3807                                         UErrorCode& status)
3808 {
3809     // run through the pattern and convert any pattern symbols from the version
3810     // in "from" to the corresponding character in "to".  This code takes
3811     // quoted strings into account (it doesn't try to translate them), and it signals
3812     // an error if a particular "pattern character" doesn't appear in "from".
3813     // Depending on the values of "from" and "to" this can convert from generic
3814     // to localized patterns or localized to generic.
3815     if (U_FAILURE(status)) {
3816         return;
3817     }
3818 
3819     translatedPattern.remove();
3820     UBool inQuote = FALSE;
3821     for (int32_t i = 0; i < originalPattern.length(); ++i) {
3822         UChar c = originalPattern[i];
3823         if (inQuote) {
3824             if (c == QUOTE) {
3825                 inQuote = FALSE;
3826             }
3827         } else {
3828             if (c == QUOTE) {
3829                 inQuote = TRUE;
3830             } else if (isSyntaxChar(c)) {
3831                 int32_t ci = from.indexOf(c);
3832                 if (ci == -1) {
3833                     status = U_INVALID_FORMAT_ERROR;
3834                     return;
3835                 }
3836                 c = to[ci];
3837             }
3838         }
3839         translatedPattern += c;
3840     }
3841     if (inQuote) {
3842         status = U_INVALID_FORMAT_ERROR;
3843         return;
3844     }
3845 }
3846 
3847 //----------------------------------------------------------------------
3848 
3849 UnicodeString&
toPattern(UnicodeString & result) const3850 SimpleDateFormat::toPattern(UnicodeString& result) const
3851 {
3852     result = fPattern;
3853     return result;
3854 }
3855 
3856 //----------------------------------------------------------------------
3857 
3858 UnicodeString&
toLocalizedPattern(UnicodeString & result,UErrorCode & status) const3859 SimpleDateFormat::toLocalizedPattern(UnicodeString& result,
3860                                      UErrorCode& status) const
3861 {
3862     translatePattern(fPattern, result,
3863                      UnicodeString(DateFormatSymbols::getPatternUChars()),
3864                      fSymbols->fLocalPatternChars, status);
3865     return result;
3866 }
3867 
3868 //----------------------------------------------------------------------
3869 
3870 void
applyPattern(const UnicodeString & pattern)3871 SimpleDateFormat::applyPattern(const UnicodeString& pattern)
3872 {
3873     fPattern = pattern;
3874     parsePattern();
3875 }
3876 
3877 //----------------------------------------------------------------------
3878 
3879 void
applyLocalizedPattern(const UnicodeString & pattern,UErrorCode & status)3880 SimpleDateFormat::applyLocalizedPattern(const UnicodeString& pattern,
3881                                         UErrorCode &status)
3882 {
3883     translatePattern(pattern, fPattern,
3884                      fSymbols->fLocalPatternChars,
3885                      UnicodeString(DateFormatSymbols::getPatternUChars()), status);
3886 }
3887 
3888 //----------------------------------------------------------------------
3889 
3890 const DateFormatSymbols*
getDateFormatSymbols() const3891 SimpleDateFormat::getDateFormatSymbols() const
3892 {
3893     return fSymbols;
3894 }
3895 
3896 //----------------------------------------------------------------------
3897 
3898 void
adoptDateFormatSymbols(DateFormatSymbols * newFormatSymbols)3899 SimpleDateFormat::adoptDateFormatSymbols(DateFormatSymbols* newFormatSymbols)
3900 {
3901     delete fSymbols;
3902     fSymbols = newFormatSymbols;
3903 }
3904 
3905 //----------------------------------------------------------------------
3906 void
setDateFormatSymbols(const DateFormatSymbols & newFormatSymbols)3907 SimpleDateFormat::setDateFormatSymbols(const DateFormatSymbols& newFormatSymbols)
3908 {
3909     delete fSymbols;
3910     fSymbols = new DateFormatSymbols(newFormatSymbols);
3911 }
3912 
3913 //----------------------------------------------------------------------
3914 const TimeZoneFormat*
getTimeZoneFormat(void) const3915 SimpleDateFormat::getTimeZoneFormat(void) const {
3916     // TimeZoneFormat initialization might fail when out of memory.
3917     // If we always initialize TimeZoneFormat instance, we can return
3918     // such status there. For now, this implementation lazily instantiates
3919     // a TimeZoneFormat for performance optimization reasons, but cannot
3920     // propagate such error (probably just out of memory case) to the caller.
3921     UErrorCode status = U_ZERO_ERROR;
3922     return (const TimeZoneFormat*)tzFormat(status);
3923 }
3924 
3925 //----------------------------------------------------------------------
3926 void
adoptTimeZoneFormat(TimeZoneFormat * timeZoneFormatToAdopt)3927 SimpleDateFormat::adoptTimeZoneFormat(TimeZoneFormat* timeZoneFormatToAdopt)
3928 {
3929     delete fTimeZoneFormat;
3930     fTimeZoneFormat = timeZoneFormatToAdopt;
3931 }
3932 
3933 //----------------------------------------------------------------------
3934 void
setTimeZoneFormat(const TimeZoneFormat & newTimeZoneFormat)3935 SimpleDateFormat::setTimeZoneFormat(const TimeZoneFormat& newTimeZoneFormat)
3936 {
3937     delete fTimeZoneFormat;
3938     fTimeZoneFormat = new TimeZoneFormat(newTimeZoneFormat);
3939 }
3940 
3941 //----------------------------------------------------------------------
3942 
3943 
adoptCalendar(Calendar * calendarToAdopt)3944 void SimpleDateFormat::adoptCalendar(Calendar* calendarToAdopt)
3945 {
3946   UErrorCode status = U_ZERO_ERROR;
3947   Locale calLocale(fLocale);
3948   calLocale.setKeywordValue("calendar", calendarToAdopt->getType(), status);
3949   DateFormatSymbols *newSymbols =
3950           DateFormatSymbols::createForLocale(calLocale, status);
3951   if (U_FAILURE(status)) {
3952       return;
3953   }
3954   DateFormat::adoptCalendar(calendarToAdopt);
3955   delete fSymbols;
3956   fSymbols = newSymbols;
3957   initializeDefaultCentury();  // we need a new century (possibly)
3958 }
3959 
3960 
3961 //----------------------------------------------------------------------
3962 
3963 
3964 // override the DateFormat implementation in order to
3965 // lazily initialize fCapitalizationBrkIter
3966 void
setContext(UDisplayContext value,UErrorCode & status)3967 SimpleDateFormat::setContext(UDisplayContext value, UErrorCode& status)
3968 {
3969     DateFormat::setContext(value, status);
3970 #if !UCONFIG_NO_BREAK_ITERATION
3971     if (U_SUCCESS(status)) {
3972         if ( fCapitalizationBrkIter == NULL && (value==UDISPCTX_CAPITALIZATION_FOR_BEGINNING_OF_SENTENCE ||
3973                 value==UDISPCTX_CAPITALIZATION_FOR_UI_LIST_OR_MENU || value==UDISPCTX_CAPITALIZATION_FOR_STANDALONE) ) {
3974             status = U_ZERO_ERROR;
3975             fCapitalizationBrkIter = BreakIterator::createSentenceInstance(fLocale, status);
3976             if (U_FAILURE(status)) {
3977                 delete fCapitalizationBrkIter;
3978                 fCapitalizationBrkIter = NULL;
3979             }
3980         }
3981     }
3982 #endif
3983 }
3984 
3985 
3986 //----------------------------------------------------------------------
3987 
3988 
3989 UBool
isFieldUnitIgnored(UCalendarDateFields field) const3990 SimpleDateFormat::isFieldUnitIgnored(UCalendarDateFields field) const {
3991     return isFieldUnitIgnored(fPattern, field);
3992 }
3993 
3994 
3995 UBool
isFieldUnitIgnored(const UnicodeString & pattern,UCalendarDateFields field)3996 SimpleDateFormat::isFieldUnitIgnored(const UnicodeString& pattern,
3997                                      UCalendarDateFields field) {
3998     int32_t fieldLevel = fgCalendarFieldToLevel[field];
3999     int32_t level;
4000     UChar ch;
4001     UBool inQuote = FALSE;
4002     UChar prevCh = 0;
4003     int32_t count = 0;
4004 
4005     for (int32_t i = 0; i < pattern.length(); ++i) {
4006         ch = pattern[i];
4007         if (ch != prevCh && count > 0) {
4008             level = getLevelFromChar(prevCh);
4009             // the larger the level, the smaller the field unit.
4010             if (fieldLevel <= level) {
4011                 return FALSE;
4012             }
4013             count = 0;
4014         }
4015         if (ch == QUOTE) {
4016             if ((i+1) < pattern.length() && pattern[i+1] == QUOTE) {
4017                 ++i;
4018             } else {
4019                 inQuote = ! inQuote;
4020             }
4021         }
4022         else if (!inQuote && isSyntaxChar(ch)) {
4023             prevCh = ch;
4024             ++count;
4025         }
4026     }
4027     if (count > 0) {
4028         // last item
4029         level = getLevelFromChar(prevCh);
4030         if (fieldLevel <= level) {
4031             return FALSE;
4032         }
4033     }
4034     return TRUE;
4035 }
4036 
4037 //----------------------------------------------------------------------
4038 
4039 const Locale&
getSmpFmtLocale(void) const4040 SimpleDateFormat::getSmpFmtLocale(void) const {
4041     return fLocale;
4042 }
4043 
4044 //----------------------------------------------------------------------
4045 
4046 int32_t
checkIntSuffix(const UnicodeString & text,int32_t start,int32_t patLoc,UBool isNegative) const4047 SimpleDateFormat::checkIntSuffix(const UnicodeString& text, int32_t start,
4048                                  int32_t patLoc, UBool isNegative) const {
4049     // local variables
4050     UnicodeString suf;
4051     int32_t patternMatch;
4052     int32_t textPreMatch;
4053     int32_t textPostMatch;
4054 
4055     // check that we are still in range
4056     if ( (start > text.length()) ||
4057          (start < 0) ||
4058          (patLoc < 0) ||
4059          (patLoc > fPattern.length())) {
4060         // out of range, don't advance location in text
4061         return start;
4062     }
4063 
4064     // get the suffix
4065     DecimalFormat* decfmt = dynamic_cast<DecimalFormat*>(fNumberFormat);
4066     if (decfmt != NULL) {
4067         if (isNegative) {
4068             suf = decfmt->getNegativeSuffix(suf);
4069         }
4070         else {
4071             suf = decfmt->getPositiveSuffix(suf);
4072         }
4073     }
4074 
4075     // check for suffix
4076     if (suf.length() <= 0) {
4077         return start;
4078     }
4079 
4080     // check suffix will be encountered in the pattern
4081     patternMatch = compareSimpleAffix(suf,fPattern,patLoc);
4082 
4083     // check if a suffix will be encountered in the text
4084     textPreMatch = compareSimpleAffix(suf,text,start);
4085 
4086     // check if a suffix was encountered in the text
4087     textPostMatch = compareSimpleAffix(suf,text,start-suf.length());
4088 
4089     // check for suffix match
4090     if ((textPreMatch >= 0) && (patternMatch >= 0) && (textPreMatch == patternMatch)) {
4091         return start;
4092     }
4093     else if ((textPostMatch >= 0) && (patternMatch >= 0) && (textPostMatch == patternMatch)) {
4094         return  start - suf.length();
4095     }
4096 
4097     // should not get here
4098     return start;
4099 }
4100 
4101 //----------------------------------------------------------------------
4102 
4103 int32_t
compareSimpleAffix(const UnicodeString & affix,const UnicodeString & input,int32_t pos) const4104 SimpleDateFormat::compareSimpleAffix(const UnicodeString& affix,
4105                    const UnicodeString& input,
4106                    int32_t pos) const {
4107     int32_t start = pos;
4108     for (int32_t i=0; i<affix.length(); ) {
4109         UChar32 c = affix.char32At(i);
4110         int32_t len = U16_LENGTH(c);
4111         if (PatternProps::isWhiteSpace(c)) {
4112             // We may have a pattern like: \u200F \u0020
4113             //        and input text like: \u200F \u0020
4114             // Note that U+200F and U+0020 are Pattern_White_Space but only
4115             // U+0020 is UWhiteSpace.  So we have to first do a direct
4116             // match of the run of Pattern_White_Space in the pattern,
4117             // then match any extra characters.
4118             UBool literalMatch = FALSE;
4119             while (pos < input.length() &&
4120                    input.char32At(pos) == c) {
4121                 literalMatch = TRUE;
4122                 i += len;
4123                 pos += len;
4124                 if (i == affix.length()) {
4125                     break;
4126                 }
4127                 c = affix.char32At(i);
4128                 len = U16_LENGTH(c);
4129                 if (!PatternProps::isWhiteSpace(c)) {
4130                     break;
4131                 }
4132             }
4133 
4134             // Advance over run in pattern
4135             i = skipPatternWhiteSpace(affix, i);
4136 
4137             // Advance over run in input text
4138             // Must see at least one white space char in input,
4139             // unless we've already matched some characters literally.
4140             int32_t s = pos;
4141             pos = skipUWhiteSpace(input, pos);
4142             if (pos == s && !literalMatch) {
4143                 return -1;
4144             }
4145 
4146             // If we skip UWhiteSpace in the input text, we need to skip it in the pattern.
4147             // Otherwise, the previous lines may have skipped over text (such as U+00A0) that
4148             // is also in the affix.
4149             i = skipUWhiteSpace(affix, i);
4150         } else {
4151             if (pos < input.length() &&
4152                 input.char32At(pos) == c) {
4153                 i += len;
4154                 pos += len;
4155             } else {
4156                 return -1;
4157             }
4158         }
4159     }
4160     return pos - start;
4161 }
4162 
4163 //----------------------------------------------------------------------
4164 
4165 int32_t
skipPatternWhiteSpace(const UnicodeString & text,int32_t pos) const4166 SimpleDateFormat::skipPatternWhiteSpace(const UnicodeString& text, int32_t pos) const {
4167     const UChar* s = text.getBuffer();
4168     return (int32_t)(PatternProps::skipWhiteSpace(s + pos, text.length() - pos) - s);
4169 }
4170 
4171 //----------------------------------------------------------------------
4172 
4173 int32_t
skipUWhiteSpace(const UnicodeString & text,int32_t pos) const4174 SimpleDateFormat::skipUWhiteSpace(const UnicodeString& text, int32_t pos) const {
4175     while (pos < text.length()) {
4176         UChar32 c = text.char32At(pos);
4177         if (!u_isUWhiteSpace(c)) {
4178             break;
4179         }
4180         pos += U16_LENGTH(c);
4181     }
4182     return pos;
4183 }
4184 
4185 //----------------------------------------------------------------------
4186 
4187 // Lazy TimeZoneFormat instantiation, semantically const.
4188 TimeZoneFormat *
tzFormat(UErrorCode & status) const4189 SimpleDateFormat::tzFormat(UErrorCode &status) const {
4190     if (fTimeZoneFormat == NULL) {
4191         umtx_lock(&LOCK);
4192         {
4193             if (fTimeZoneFormat == NULL) {
4194                 TimeZoneFormat *tzfmt = TimeZoneFormat::createInstance(fLocale, status);
4195                 if (U_FAILURE(status)) {
4196                     return NULL;
4197                 }
4198 
4199                 const_cast<SimpleDateFormat *>(this)->fTimeZoneFormat = tzfmt;
4200             }
4201         }
4202         umtx_unlock(&LOCK);
4203     }
4204     return fTimeZoneFormat;
4205 }
4206 
parsePattern()4207 void SimpleDateFormat::parsePattern() {
4208     fHasMinute = FALSE;
4209     fHasSecond = FALSE;
4210 
4211     int len = fPattern.length();
4212     UBool inQuote = FALSE;
4213     for (int32_t i = 0; i < len; ++i) {
4214         UChar ch = fPattern[i];
4215         if (ch == QUOTE) {
4216             inQuote = !inQuote;
4217         }
4218         if (!inQuote) {
4219             if (ch == 0x6D) {  // 0x6D == 'm'
4220                 fHasMinute = TRUE;
4221             }
4222             if (ch == 0x73) {  // 0x73 == 's'
4223                 fHasSecond = TRUE;
4224             }
4225         }
4226     }
4227 }
4228 
4229 U_NAMESPACE_END
4230 
4231 #endif /* #if !UCONFIG_NO_FORMATTING */
4232 
4233 //eof
4234