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