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