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