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