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