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