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