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