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