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