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