• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&param, 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