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